Postgres em produção: gerenciado vs auto-hospedado, a conta honesta

RDS começa US$15/mês — termina US$500. Auto-hospedar começa $0 — termina te acordando às 3 da manhã. Como decidir entre os dois sem mentir pra você.

Equipe HeroCtl··14 min

A decisão "RDS ou rodo Postgres no meu cluster" é a que SaaS brasileiro mais adia. Ela aparece num documento de arquitetura no mês um, vira um TODO no mês três, vira uma briga interna no mês seis quando a fatura da AWS chega em três dígitos altos. E enquanto isso, ninguém quer escolher — porque cada blog post sobre o assunto é escrito por alguém com viés. Quem trabalha em fornecedor gerenciado fala que self-hosted te quebra. Quem mantém Postgres há quinze anos fala que RDS é roubo. Os dois lados omitem coisa.

Este post abre a planilha de verdade. Sem floreio, sem vender lado. Quando RDS faz sentido, quando não faz, quanto custa cada cenário em real, quanto custa em hora de engenheiro, e quais são os cinco erros que fazem self-hosted virar acidente.

O que serviços gerenciados fazem por você (sem ironia)

Antes de qualquer comparação, é honesto reconhecer o que RDS, Cloud SQL, Aurora e os Postgres-as-a-Service modernos (Supabase, Neon, Crunchy) entregam de fato. A propaganda inflou — mas o produto é real.

Backup automático com retenção configurável. Você diz "guarda sete dias", e está feito. Snapshot incremental, sem janela de manutenção visível, sem cron, sem baby-sitter. Para muitos times, esse item sozinho justifica o cheque.

Recuperação ponto-no-tempo (PITR). Você descobre às onze da manhã que um deploy às nove apagou um campo importante. Em RDS, você restaura para 08:55. Sem ler manual de WAL archiving, sem rezar pra um log de transações estar íntegro num bucket. Apenas console e botão.

Patches de segurança automáticos. Postgres minor releases saem a cada três meses, e cada um tem CVE razoável. Em gerenciado, isso aplica numa janela que você define. Em self-hosted, você descobre que está atrasado quando uma checagem de compliance bate.

Réplica de leitura em um clique. Quer escalar leitura? Liga a réplica, espera replicar, aponta a sua aplicação. Em self-hosted, você configura streaming replication manualmente, gerencia slot de replicação, monitora atraso, define o que acontece se a conexão cair.

Failover Multi-AZ automático. Em RDS Multi-AZ, a instância secundária assume em 60–120 segundos quando a primária morre, e o endpoint DNS roteia sozinho. É a feature mais cara e a mais útil do produto.

Métricas integradas, logs centralizados. CloudWatch já tem tudo lá. Slow queries, cache hit ratio, conexões ativas, IO. Você abre o console e vê.

Horas de operação que você não passa. Esse é o item invisível. Cada uma das features acima é uma tarde que você não gastou. Vinte tardes ao longo do ano viram um engenheiro inteiro de dedicação parcial.

Reconhecer isso é o ponto de partida honesto. RDS é um produto sério. Não é vento.

O que serviços gerenciados NÃO fazem (e ninguém fala)

Aqui mora o asterisco. As limitações abaixo não estão na primeira página da documentação.

Migrar pra outra plataforma vira projeto. Quando você está em Aurora, sair de Aurora é um projeto de duas a doze semanas dependendo do tamanho. O dialeto não é puro Postgres — Aurora tem extensões e comportamentos próprios. Sair de Cloud SQL pra outra nuvem exige dump-restore, downtime planejado, reescrita de scripts, ajuste de IAM, refazer monitoramento. O custo de saída é o que financia o desconto da entrada.

Algumas extensões populares simplesmente não existem. TimescaleDB não roda em RDS (a AWS oferece um equivalente próprio que não é compatível). pg_partman tem versão antiga. pgvector chegou tarde. Se a sua arquitetura depende de uma extensão específica, você pode descobrir três meses depois que ela não está disponível na sua região, na sua versão, ou em geral.

Tráfego de saída entre regiões custa. Você decide colocar uma réplica em outra região pra disaster recovery. Cada gigabyte saindo da região principal pra secundária paga pedágio. Em workloads pequenos é desprezível. Em workloads de 200 GB de write por dia, vira uma fatura paralela.

Latência entre app e banco se eles estiverem em VPCs diferentes. Esse é o erro silencioso. Você sobe o app numa rede e o banco em outra, com peering. A latência mínima vai de 0,3 ms (mesma rede) pra 2–4 ms (peering). Não parece muito até a sua aplicação fazer cento e vinte queries por requisição — aí viram 350 ms de latência fantasma.

Auditoria detalhada custa extra. Quem fez DROP TABLE? Em RDS isso pede Performance Insights na faixa avançada (US$7 por vCPU por mês) mais um logging plugin. Não vem ligado.

Você não controla a janela de manutenção de verdade. Você "configura" uma janela, mas em incidentes graves a AWS aplica patches fora dela. Já aconteceu, vai acontecer.

A conta financeira honesta

Câmbio de referência: R$5 por dólar. Preços de RDS em região São Paulo (sa-east-1), abril/2026, on-demand. Self-hosted assume VPS DigitalOcean / Vultr / Hetzner em São Paulo ou Miami.

Cenário pequeno: banco abaixo de 10 GB, até 100 conexões/seg

ItemRDSSelf-hosted
Instânciadb.t4g.micro (2 vCPU burst, 1 GB RAM)VPS 2 vCPU 4 GB já existente do app
Custo mensalUS$15 = R$75R$0 (cabe junto do app)
Storage 10 GB gp3US$1,15incluso
Backup 10 GBUS$0,95R$0,50 (S3-compatible)
TotalR$85/mêsR$0,50/mês

Diferença: R$84/mês. Em um ano, R$1 mil. Não muda a vida de ninguém. Para um MVP, RDS é defensável só pelo backup automático.

Cenário médio: 50 GB, 1 mil conexões/seg, 1 réplica de leitura

ItemRDSSelf-hosted
Primáriadb.r6g.large (2 vCPU, 16 GB)VPS dedicado 4 vCPU, 8 GB — R$120
Réplica leituradb.r6g.largeVPS 4 vCPU, 8 GB — R$120
Storage 50 GB gp3US$5,75incluso
IOPS provisionado 3000US$60incluso
Backup 50 GBUS$4,75R$5 (objeto compatível)
BandwidthUS$10incluso
TotalUS$280 = R$1.400/mêsR$245/mês

Diferença: R$1.155/mês = R$13,8 mil/ano. Aqui a conversa começa. Vale R$14 mil pra não pensar em backup? Para um time de dois engenheiros, é um mês de trabalho de um deles. Para um time de oito, é desprezível.

Cenário grande: 500 GB, 10 mil conexões/seg, alta disponibilidade real

ItemRDS Multi-AZSelf-hosted cluster
Primáriadb.r6g.4xlarge (16 vCPU, 128 GB) Multi-AZVPS dedicado 16 vCPU, 64 GB — R$650
Réplica síncrona Multi-AZinclusaVPS dedicado 16 vCPU, 64 GB — R$650
Réplica de leituradb.r6g.2xlargeVPS 8 vCPU, 32 GB — R$320
Storage 500 GB io1US$60incluso
IOPS provisionado 10 milUS$650NVMe local incluso
Backup automático 500 GBUS$48R$80 (WAL archiving)
Performance Insights avançadoUS$112grátis (Prometheus)
Bandwidth saídaUS$100incluso até 20 TB
TotalUS$2.100 = R$10,5 mil/mêsR$1.700/mês

Diferença: R$8,8 mil/mês = R$105 mil/ano. Aqui é onde o gerenciado fica difícil de defender financeiramente. Mas a conta financeira é só metade. A outra metade é tempo.

A conta de tempo (mais importante que a financeira)

Tempo de engenheiro em São Paulo custa entre R$80 e R$250 por hora útil dependendo do nível. Considere R$150/hora como média ponderada. Esse é o multiplicador que você precisa cruzar com cada item abaixo.

Setup inicial. RDS via console: trinta minutos. Você define instância, storage, security group, parameter group, e está rodando. Self-hosted bem feito: quatro a oito horas. Postgres + PgBouncer + pgBackRest pra S3 + monitoring + tunning de shared_buffers/work_mem + script de restore + teste de restore. Fazer isso em meio dia exige experiência prévia. Sem experiência, vira um sprint inteiro.

Operação contínua mensal. RDS: zero. Você abre o console quando algo grita. Self-hosted bem feito: duas a quatro horas. Revisar slow queries, ajustar parâmetro que ficou apertado, verificar que backup foi feito, restore test mensal, atualizar versão menor. Isso é o regime de cruzeiro. Se você está gastando mais que isso, está acontecendo problema.

Quando dá pau às três da manhã. Em RDS, você abre ticket. Plano Business da AWS responde em quatro horas para severidade alta, uma hora para crítica. Você vai dormir e acorda com workaround. Em self-hosted, você é o suporte. Se o seu sistema de monitoramento não acordou você, o cliente acordou. Se o seu plano de DR está num documento que ninguém leu há seis meses, você está improvisando.

A regra clara: ter monitoramento, plano de recuperação de desastre escrito, e teste mensal de restore — não é opcional em self-hosted. É o que separa "self-hosted profissional" de "acidente esperando acontecer".

Stack mínima pra Postgres self-hosted production-grade

Não dá pra rodar Postgres em produção sem essa base. Cada componente abaixo resolve um modo de falha conhecido.

Postgres principal em servidor dedicado. Não compartilhe disco com a aplicação. O motor depende de IOPS previsíveis, e um log do app crescendo descontrolado pode encher o volume e parar o banco. Aloque um VPS só pro banco, ou um volume separado se for o mesmo VPS no início.

Pool de conexões com PgBouncer ou Pgpool. Postgres aloca um processo por conexão. Em duzentas conexões diretas, ele consome mais memória que a sua aplicação. PgBouncer em modo transaction resolve: dezenas de conexões reais ao banco servindo milhares de conexões da aplicação. Sem isso, você morre na primeira hora de pico.

Backup com pgBackRest ou WAL-E. Não use pg_dump em cron como estratégia única. pg_dump é dump lógico — bom pra migrar versão, ruim pra recuperar banco grande no minuto certo. Você quer pg_basebackup semanal mais arquivamento contínuo de WAL pra um bucket compatível com S3 (R2 da Cloudflare, B2 da Backblaze, Wasabi, ou o próprio S3). pgBackRest faz isso e ainda valida integridade.

Réplica em hot standby por replicação em streaming. Um segundo servidor recebendo o WAL em tempo real, pronto pra promover se o primário cair. Bônus: você usa esse mesmo servidor pra queries de leitura pesada, descarregando o primário.

Monitoramento com postgres_exporter + Prometheus + Grafana, ou um plug-in equivalente do orquestrador que você usa. Você quer ver: conexões ativas, ratio de cache, taxa de transações, lag de replicação, espaço em disco, slow queries. Sem isso, você está dirigindo de olho fechado.

Teste de restore mensal automatizado. Cron que pega o backup mais recente, restaura num servidor temporário, valida que algumas tabelas têm linhas. Se isso falhar, alerta o time. Backup que nunca foi restaurado é placebo. Já vimos times perderem semana inteira de dados porque o "backup" estava corrompido há três meses e ninguém testou.

Os cinco erros que quebram self-hosted Postgres

São os mesmos cinco há quinze anos. Não inovam.

Não testar restore. Repetimos porque é o item mais comum. Backup que nunca foi restaurado não é backup, é arquivo. Restore mensal automatizado é o mínimo civilizado.

Manter shared_buffers e work_mem no padrão. O padrão do Postgres é projetado pra rodar num servidor pequeno sem assumir nada. Em produção, shared_buffers deve ser 25% da RAM, effective_cache_size 50–75%, work_mem calculado por conexão simultânea. Sem isso, você tem 64 MB de cache num servidor com 16 GB de RAM e o desempenho está deixado na mesa.

Não monitorar consultas lentas. Uma query mal escrita por um desenvolvedor distraído pode travar o banco inteiro. pg_stat_statements ligado, alerta pra qualquer query passando de 500 ms em produção. Sem isso, você descobre o problema quando o cliente abre ticket.

Disco compartilhado com o sistema operacional. O log do sistema enche, o /var do banco compartilha o mesmo volume, e o banco para de aceitar escrita. Postgres tem que estar em volume dedicado. NVMe se possível.

Um servidor só sem réplica. Servidor cai — e cai, mais cedo ou mais tarde, hardware falha — e você está com downtime de uma a três horas restaurando do backup. Réplica síncrona em outro servidor reduz isso pra segundos.

Postgres num orquestrador como o HeroCtl

Aqui é onde a complexidade operacional cai. Não porque o Postgres ficou mais simples — ele continua complexo — mas porque o orquestrador absorve a parte de plumbing que normalmente você escreve à mão.

Postgres como tarefa do cluster. A descrição do serviço é um arquivo de configuração de aproximadamente trinta linhas: imagem oficial do Postgres, volume nomeado pra dados, variáveis de ambiente pra credenciais, recurso reservado de CPU e memória, política de reinício. Sem systemd unit, sem apt install, sem firewall manual.

Persistência via volume nomeado replicado. Você diz "esse volume é replicado entre dois servidores", e o orquestrador garante que os dados existem nos dois. Se o servidor que está rodando o Postgres cair, o cluster reagenda no segundo servidor com os dados já presentes. Tempo de recuperação na casa de segundos, não horas.

Backup automático integrado no plano Business: arquivamento contínuo de WAL pra objeto compatível com S3, snapshot semanal, retenção configurável. A mesma feature do RDS, sem cheque pra AWS.

Réplica de leitura como tarefa adicional. Você descreve um segundo serviço que aponta pro primeiro como upstream de replicação. Cinco linhas extras no manifesto. Sem console, sem clique, sem etapa manual.

Métricas embutidas. O orquestrador já está coletando CPU, memória, IO de cada contêiner. Adicionar postgres_exporter é mais uma tarefa de quinze linhas. Sem montar Prometheus separado, sem provisionar Grafana, sem estourar mais um servidor.

Failover automático se o servidor que coordena cair: o cluster elege outro coordenador em torno de sete segundos e continua agendando. O Postgres em si volta nos servidores que sobraram em seguida.

A descrição completa de um Postgres com réplica + backup + métricas no HeroCtl é em torno de cem linhas. Em Kubernetes, o equivalente é um operador externo (CloudNativePG ou Zalando) mais 300 linhas de manifesto, mais um stack de monitoramento separado, mais cert-manager pra TLS interno entre nós. Para o time de cinco pessoas, a diferença é entre uma tarde e uma sprint.

Tabela comparativa

CritérioRDS São PauloCloud SQLSupabaseNeonPostgres VPS simplesPostgres no HeroCtl
Custo mínimo (50 GB médio)R$1.400/mêsR$1.300/mêsR$125/mês (Pro)R$95/mês (Launch)R$240/mêsR$245/mês
Backup automáticosimsimsimsimvocê configurasim (Business)
Recuperação ponto-no-temposimsimsim (Pro)simvocê configurasim (Business)
Alta disponibilidade realsim (Multi-AZ pago)simparcialsimvocê configurasim
Extensões customizadasrestritorestritorestritorestritototaltotal
Lock-inaltoaltomédiomédionenhumnenhum
Migração de saídasemanassemanasdiasdiashorashoras
Monitoramento inclusoparcialsimsimsimvocê montaembutido
Expertise mínimanenhumanenhumanenhumanenhumasêniorpleno
Latência app↔banco1–4 ms1–4 ms5–30 ms10–50 ms0,3 ms0,3 ms
Faixa idealqualquerqualqueraté 50 GBaté 100 GBindiestartup a porte médio
Compliance LGPD via fornecedorsimsimparcialparcialvocê documentavocê documenta

Nenhuma coluna ganha em tudo. Cada uma é um conjunto coerente de tradeoffs. Quem tenta vender uma coluna como "a melhor" está vendendo.

Decisão honesta por perfil

MVP até 10 GB e até cem conexões/seg. Postgres como contêiner ao lado da aplicação, num único VPS. Backup diário pra objeto compatível com S3. Custo total, banco e tudo, na faixa de R$10/mês acima do que você já paga pelo VPS. Em algum momento você migra — e migrar com 10 GB é uma noite de domingo, não um projeto. Comece simples.

Indie hacker entre 10 e 100 GB. Postgres em VPS dedicado, réplica assíncrona em segundo VPS, backup horário pra objeto S3-compatible (Cloudflare R2 ou Backblaze B2 sai a centavos). Algo entre R$120 e R$200 por mês total. Se você tem hora pra dedicar, esse é o ponto onde self-hosted compensa muito.

Startup early entre 100 e 500 GB. Aqui a decisão fica de verdade. Avalie RDS São Paulo pelo argumento de compliance LGPD (a AWS já tem o caderno de certificações do datacenter) — vai sair na faixa de R$1,5 a R$3 mil por mês. Ou avalie Postgres em cluster gerenciado pelo orquestrador, em três VPS dedicados, na faixa de R$400 por mês — mas exige disciplina operacional real. Não é "self-hosted descomplicado". É self-hosted com orquestrador absorvendo a parte de plumbing.

Compliance pesada ou Enterprise. Gerenciado faz sentido quando o framework de auditoria pede fornecedor com certificação específica. Mas leia o contrato — algumas regiões de RDS no Brasil ainda não têm todas as certificações (HIPAA, FedRAMP, PCI nível 1) que a região americana tem. Se o seu auditor pede um certificado específico, confirme que a região tem antes de assinar.

Perguntas que time inexperiente faz

Posso começar com self-hosted e migrar pra RDS depois? Pode, e é uma estratégia válida. Postgres é Postgres. Você faz pg_dump da base, restaura em RDS, ajusta endpoint da aplicação, descomissiona o servidor antigo. Para até 50 GB, é uma operação de algumas horas com janela curta. O caminho contrário (sair de RDS pra self-hosted) também funciona, mas ferramentas como AWS DMS facilitam mais o ingresso que a saída.

RDS São Paulo é confiável? A região sa-east-1 é uma das mais antigas da AWS fora dos Estados Unidos, opera desde 2011, e tem três zonas de disponibilidade independentes. Em incidentes globais da AWS, São Paulo costuma ser pega junto. Em incidentes regionais, ela cai sozinha — o que aconteceu duas vezes nos últimos cinco anos por algumas horas. Confiável o suficiente pra produção, não confiável o suficiente pra dispensar plano B.

Backup com pg_dump em cron resolve? Resolve pra MVP, não resolve pra produção séria. pg_dump é dump lógico — não preserva o estado exato, perde no tempo de restore (lento pra bases grandes), e não permite recuperar pro minuto X. A combinação certa é pg_basebackup físico semanal mais arquivamento contínuo de WAL. Ferramenta: pgBackRest.

Quando vale comprar Performance Insights na faixa avançada? Quando você está em RDS, tem mais de cinco engenheiros mexendo no schema, e precisa rastrear "quem rodou essa query?". Em times pequenos, o pg_stat_statements nativo já entrega 80% do valor — ative ele primeiro e veja se você precisa de mais.

E Supabase, Neon, Crunchy? São produtos diferentes em cima de Postgres. Supabase é Postgres + autenticação + API REST gerada + storage de arquivos — bom pra projeto que precisa de tudo isso integrado, ruim pra quem quer só banco. Neon separa storage e compute, dorme quando ocioso, ótimo pra ambiente de staging e workload spiky. Crunchy é Postgres puro com foco enterprise e operador para Kubernetes. Os três têm camadas grátis razoáveis pra MVP — vale testar antes de fechar com RDS.

Como faço HA real sem RDS Multi-AZ? Réplica síncrona em segundo servidor (synchronous_standby_names configurado) garante que cada commit foi escrito nos dois antes de retornar OK pra aplicação. Failover via Patroni, ou via orquestrador como o HeroCtl. O ponto sensível é o split-brain: a réplica não pode promover sozinha sem confirmação externa. Patroni resolve com etcd como árbitro. HeroCtl resolve com o próprio plano de controle distribuído fazendo o papel de árbitro — sem montar serviço extra.

HeroCtl roda Postgres pesado em produção mesmo? Roda. O cluster público da própria documentação serve esse blog através de uma stack que inclui um Postgres self-hosted como tarefa do cluster, com réplica e backup. Para workloads acima de 500 GB ou com requisitos de IOPS na casa de 50 mil, recomendamos avaliar gerenciado — não porque o orquestrador não aguenta, mas porque o IOPS provisionado e o controle de I/O da AWS naquela faixa começam a fazer diferença operacional real.

Fechamento

Não existe resposta única pra "Postgres gerenciado ou auto-hospedado". Existe a sua planilha. Se você abriu este post procurando confirmação, o que achou foi números — use eles.

Para os perfis em que self-hosted compensa mas a operação assusta, o HeroCtl é a camada que reduz o atrito. Backup, réplica, monitoramento e failover descritos em cem linhas de configuração, rodando no seu cluster, sem cheque pra fornecedor, sem lock-in.

Instale com:

curl -sSL get.heroctl.com/install.sh | sh

Para mais sobre o custo total de hospedar SaaS no Brasil em 2026, leia quanto custa hospedar SaaS brasileiro. Para a transição prática de Docker Compose pra cluster com alta disponibilidade real, leia deploy Docker em produção, do Compose ao cluster.

A conta honesta é a que cabe na sua planilha. Faça os números antes de decidir.

#postgres#banco-de-dados#rds#self-hosted#engenharia