[{"data":1,"prerenderedAt":1155},["ShallowReactive",2],{"blog-en-\u002Fen\u002Fblog\u002Fpostgres-in-production-managed-vs-self-hosted":3,"blog-en-surround-\u002Fen\u002Fblog\u002Fpostgres-in-production-managed-vs-self-hosted":1142},{"id":4,"title":5,"author":6,"body":7,"category":1123,"cover":1124,"date":1125,"description":1126,"draft":1127,"extension":1128,"lastReviewed":1124,"meta":1129,"navigation":1130,"path":1131,"readingTime":1132,"seo":1133,"sitemap":1134,"stem":1135,"tags":1136,"__hash__":1141},"blog_en\u002Fen\u002Fblog\u002Fpostgres-in-production-managed-vs-self-hosted.md","Postgres in production: managed vs self-hosted, the honest math","HeroCtl team",{"type":8,"value":9,"toc":1104},"minimark",[10,14,17,22,25,32,38,44,50,56,62,68,71,75,78,84,90,96,102,108,114,118,126,131,219,222,226,319,326,330,444,451,455,458,472,478,484,487,491,494,500,510,527,533,543,549,553,556,562,584,594,604,610,614,617,631,637,643,649,658,664,667,671,938,941,945,951,957,963,969,973,982,991,1006,1015,1021,1031,1037,1041,1044,1047,1050,1083,1097,1100],[11,12,13],"p",{},"The \"RDS or run Postgres on my cluster\" decision is the one Brazilian SaaS most postpones. It shows up in a month-one architecture document, becomes a TODO in month three, becomes an internal fight in month six when the AWS bill comes in high three digits. And meanwhile, no one wants to choose — because every blog post on the subject is written by someone with bias. Those who work for a managed vendor say self-hosted will break you. Those who've maintained Postgres for fifteen years say RDS is a rip-off. Both sides leave things out.",[11,15,16],{},"This post opens the real spreadsheet. No frills, no taking sides. When RDS makes sense, when it doesn't, how much each scenario costs in reais, how much it costs in engineer-hours, and what the five mistakes are that turn self-hosted into an accident.",[18,19,21],"h2",{"id":20},"what-managed-services-do-for-you-no-irony","What managed services do for you (no irony)",[11,23,24],{},"Before any comparison, it's honest to recognize what RDS, Cloud SQL, Aurora, and modern Postgres-as-a-Service (Supabase, Neon, Crunchy) actually deliver. The marketing inflated it — but the product is real.",[11,26,27,31],{},[28,29,30],"strong",{},"Automatic backup with configurable retention."," You say \"keep seven days,\" and it's done. Incremental snapshot, no visible maintenance window, no cron, no babysitter. For many teams, this item alone justifies the check.",[11,33,34,37],{},[28,35,36],{},"Point-in-time recovery (PITR)."," You discover at eleven a.m. that a deploy at nine deleted an important field. In RDS, you restore to 08:55. No reading the WAL archiving manual, no praying for a transaction log to be intact in a bucket. Just console and button.",[11,39,40,43],{},[28,41,42],{},"Automatic security patches."," Postgres minor releases come out every three months, and each has a reasonable CVE. In managed, that applies in a window you define. In self-hosted, you discover you're behind when a compliance check hits.",[11,45,46,49],{},[28,47,48],{},"One-click read replica."," Want to scale reads? Turn on the replica, wait for replication, point your application. In self-hosted, you configure streaming replication manually, manage replication slot, monitor lag, define what happens if the connection drops.",[11,51,52,55],{},[28,53,54],{},"Automatic Multi-AZ failover."," In RDS Multi-AZ, the secondary instance takes over in 60–120 seconds when the primary dies, and the DNS endpoint routes itself. It's the most expensive and most useful feature of the product.",[11,57,58,61],{},[28,59,60],{},"Integrated metrics, centralized logs."," CloudWatch already has everything there. Slow queries, cache hit ratio, active connections, IO. You open the console and see.",[11,63,64,67],{},[28,65,66],{},"Hours of operation you don't spend."," This is the invisible item. Each of the features above is an afternoon you didn't spend. Twenty afternoons over the year add up to a whole engineer of part-time dedication.",[11,69,70],{},"Recognizing this is the honest starting point. RDS is a serious product. It's not air.",[18,72,74],{"id":73},"what-managed-services-do-not-do-and-no-one-talks-about","What managed services do NOT do (and no one talks about)",[11,76,77],{},"Here lives the asterisk. The limitations below aren't on page one of the documentation.",[11,79,80,83],{},[28,81,82],{},"Migrating to another platform becomes a project."," When you're in Aurora, leaving Aurora is a two-to-twelve-week project depending on the size. The dialect isn't pure Postgres — Aurora has its own extensions and behaviors. Leaving Cloud SQL for another cloud requires dump-restore, planned downtime, script rewrite, IAM tuning, redoing monitoring. The exit cost is what funds the entry discount.",[11,85,86,89],{},[28,87,88],{},"Some popular extensions simply don't exist."," TimescaleDB doesn't run on RDS (AWS offers its own equivalent that isn't compatible). pg_partman has an old version. pgvector arrived late. If your architecture depends on a specific extension, you may discover three months later that it isn't available in your region, in your version, or at all.",[11,91,92,95],{},[28,93,94],{},"Cross-region egress traffic costs."," You decide to put a replica in another region for disaster recovery. Each gigabyte leaving the main region for the secondary pays toll. In small workloads it's negligible. In workloads with 200 GB of write per day, it becomes a parallel bill.",[11,97,98,101],{},[28,99,100],{},"Latency between app and database if they're in different VPCs."," This is the silent error. You bring up the app on one network and the database on another, with peering. Minimum latency goes from 0.3 ms (same network) to 2–4 ms (peering). Doesn't seem like much until your application makes one hundred and twenty queries per request — then it becomes 350 ms of phantom latency.",[11,103,104,107],{},[28,105,106],{},"Detailed auditing costs extra."," Who ran DROP TABLE? In RDS that asks for Performance Insights at the advanced tier (US$7 per vCPU per month) plus a logging plugin. It doesn't come on.",[11,109,110,113],{},[28,111,112],{},"You don't really control the maintenance window."," You \"configure\" a window, but in serious incidents AWS applies patches outside it. It's happened, it'll happen.",[18,115,117],{"id":116},"the-honest-financial-math","The honest financial math",[11,119,120,121,125],{},"Reference exchange rate: R$5 per dollar. RDS prices in São Paulo region (",[122,123,124],"code",{},"sa-east-1","), April 2026, on-demand. Self-hosted assumes DigitalOcean \u002F Vultr \u002F Hetzner VPS in São Paulo or Miami.",[127,128,130],"h3",{"id":129},"small-scenario-database-under-10-gb-up-to-100-connectionssec","Small scenario: database under 10 GB, up to 100 connections\u002Fsec",[132,133,134,150],"table",{},[135,136,137],"thead",{},[138,139,140,144,147],"tr",{},[141,142,143],"th",{},"Item",[141,145,146],{},"RDS",[141,148,149],{},"Self-hosted",[151,152,153,165,182,193,204],"tbody",{},[138,154,155,159,162],{},[156,157,158],"td",{},"Instance",[156,160,161],{},"db.t4g.micro (2 vCPU burst, 1 GB RAM)",[156,163,164],{},"2 vCPU 4 GB VPS already used by the app",[138,166,167,170,176],{},[156,168,169],{},"Monthly cost",[156,171,172,173],{},"US$15 = ",[28,174,175],{},"R$75",[156,177,178,181],{},[28,179,180],{},"R$0"," (fits alongside the app)",[138,183,184,187,190],{},[156,185,186],{},"10 GB gp3 storage",[156,188,189],{},"US$1.15",[156,191,192],{},"included",[138,194,195,198,201],{},[156,196,197],{},"10 GB backup",[156,199,200],{},"US$0.95",[156,202,203],{},"R$0.50 (S3-compatible)",[138,205,206,209,214],{},[156,207,208],{},"Total",[156,210,211],{},[28,212,213],{},"R$85\u002Fmonth",[156,215,216],{},[28,217,218],{},"R$0.50\u002Fmonth",[11,220,221],{},"Difference: R$84\u002Fmonth. In a year, R$1k. Doesn't change anyone's life. For an MVP, RDS is defensible just for the automatic backup.",[127,223,225],{"id":224},"medium-scenario-50-gb-1k-connectionssec-1-read-replica","Medium scenario: 50 GB, 1k connections\u002Fsec, 1 read replica",[132,227,228,238],{},[135,229,230],{},[138,231,232,234,236],{},[141,233,143],{},[141,235,146],{},[141,237,149],{},[151,239,240,251,262,272,282,293,303],{},[138,241,242,245,248],{},[156,243,244],{},"Primary",[156,246,247],{},"db.r6g.large (2 vCPU, 16 GB)",[156,249,250],{},"Dedicated 4 vCPU, 8 GB VPS — R$120",[138,252,253,256,259],{},[156,254,255],{},"Read replica",[156,257,258],{},"db.r6g.large",[156,260,261],{},"4 vCPU, 8 GB VPS — R$120",[138,263,264,267,270],{},[156,265,266],{},"50 GB gp3 storage",[156,268,269],{},"US$5.75",[156,271,192],{},[138,273,274,277,280],{},[156,275,276],{},"3000 provisioned IOPS",[156,278,279],{},"US$60",[156,281,192],{},[138,283,284,287,290],{},[156,285,286],{},"50 GB backup",[156,288,289],{},"US$4.75",[156,291,292],{},"R$5 (S3-compatible)",[138,294,295,298,301],{},[156,296,297],{},"Bandwidth",[156,299,300],{},"US$10",[156,302,192],{},[138,304,305,309,314],{},[156,306,307],{},[28,308,208],{},[156,310,311],{},[28,312,313],{},"US$280 = R$1,400\u002Fmonth",[156,315,316],{},[28,317,318],{},"R$245\u002Fmonth",[11,320,321,322,325],{},"Difference: R$1,155\u002Fmonth = ",[28,323,324],{},"R$13.8k\u002Fyear",". Here the conversation begins. Is it worth R$14k not to think about backup? For a team of two engineers, that's a month of one of their work. For a team of eight, it's negligible.",[127,327,329],{"id":328},"large-scenario-500-gb-10k-connectionssec-real-high-availability","Large scenario: 500 GB, 10k connections\u002Fsec, real high availability",[132,331,332,344],{},[135,333,334],{},[138,335,336,338,341],{},[141,337,143],{},[141,339,340],{},"RDS Multi-AZ",[141,342,343],{},"Self-hosted cluster",[151,345,346,356,365,375,384,395,406,417,428],{},[138,347,348,350,353],{},[156,349,244],{},[156,351,352],{},"db.r6g.4xlarge (16 vCPU, 128 GB) Multi-AZ",[156,354,355],{},"Dedicated 16 vCPU, 64 GB VPS — R$650",[138,357,358,361,363],{},[156,359,360],{},"Multi-AZ sync replica",[156,362,192],{},[156,364,355],{},[138,366,367,369,372],{},[156,368,255],{},[156,370,371],{},"db.r6g.2xlarge",[156,373,374],{},"8 vCPU, 32 GB VPS — R$320",[138,376,377,380,382],{},[156,378,379],{},"500 GB io1 storage",[156,381,279],{},[156,383,192],{},[138,385,386,389,392],{},[156,387,388],{},"10k provisioned IOPS",[156,390,391],{},"US$650",[156,393,394],{},"local NVMe included",[138,396,397,400,403],{},[156,398,399],{},"500 GB automatic backup",[156,401,402],{},"US$48",[156,404,405],{},"R$80 (WAL archiving)",[138,407,408,411,414],{},[156,409,410],{},"Performance Insights advanced",[156,412,413],{},"US$112",[156,415,416],{},"free (Prometheus)",[138,418,419,422,425],{},[156,420,421],{},"Egress bandwidth",[156,423,424],{},"US$100",[156,426,427],{},"included up to 20 TB",[138,429,430,434,439],{},[156,431,432],{},[28,433,208],{},[156,435,436],{},[28,437,438],{},"US$2,100 = R$10.5k\u002Fmonth",[156,440,441],{},[28,442,443],{},"R$1,700\u002Fmonth",[11,445,446,447,450],{},"Difference: R$8.8k\u002Fmonth = ",[28,448,449],{},"R$105k\u002Fyear",". This is where managed becomes hard to defend financially. But the financial math is only half. The other half is time.",[18,452,454],{"id":453},"the-time-math-more-important-than-the-financial","The time math (more important than the financial)",[11,456,457],{},"Engineer time in São Paulo costs between R$80 and R$250 per useful hour depending on level. Consider R$150\u002Fhour as a weighted average. That's the multiplier you need to cross with each item below.",[11,459,460,463,464,467,468,471],{},[28,461,462],{},"Initial setup."," RDS via console: thirty minutes. You define instance, storage, security group, parameter group, and it's running. Self-hosted done right: four to eight hours. Postgres + PgBouncer + pgBackRest to S3 + monitoring + tuning of ",[122,465,466],{},"shared_buffers","\u002F",[122,469,470],{},"work_mem"," + restore script + restore test. Doing this in half a day requires prior experience. Without experience, it becomes a whole sprint.",[11,473,474,477],{},[28,475,476],{},"Ongoing monthly operation."," RDS: zero. You open the console when something screams. Self-hosted done right: two to four hours. Review slow queries, adjust a parameter that got tight, verify backup ran, monthly restore test, update minor version. That's the cruise regime. If you're spending more than that, problems are happening.",[11,479,480,483],{},[28,481,482],{},"When it breaks at three a.m."," In RDS, you open a ticket. AWS Business plan responds in four hours for high severity, one hour for critical. You go to bed and wake up with a workaround. In self-hosted, you are the support. If your monitoring system didn't wake you up, the customer did. If your DR plan is in a document no one has read in six months, you're improvising.",[11,485,486],{},"The clear rule: having monitoring, written disaster recovery plan, and monthly restore test — is not optional in self-hosted. It's what separates \"professional self-hosted\" from \"accident waiting to happen\".",[18,488,490],{"id":489},"minimum-stack-for-production-grade-self-hosted-postgres","Minimum stack for production-grade self-hosted Postgres",[11,492,493],{},"You can't run Postgres in production without this base. Each component below solves a known failure mode.",[11,495,496,499],{},[28,497,498],{},"Main Postgres on dedicated server."," Don't share disk with the application. The engine depends on predictable IOPS, and an uncontrolled growing app log can fill the volume and stop the database. Allocate a VPS just for the database, or a separate volume if it's the same VPS at first.",[11,501,502,505,506,509],{},[28,503,504],{},"Connection pool with PgBouncer or Pgpool."," Postgres allocates one process per connection. At two hundred direct connections, it consumes more memory than your application. PgBouncer in ",[122,507,508],{},"transaction"," mode solves it: dozens of real connections to the database serving thousands of application connections. Without it, you die in the first peak hour.",[11,511,512,515,516,519,520,522,523,526],{},[28,513,514],{},"Backup with pgBackRest or WAL-E."," Don't use ",[122,517,518],{},"pg_dump"," in cron as a sole strategy. ",[122,521,518],{}," is a logical dump — good for migrating versions, bad for recovering a large database at a precise moment. You want weekly ",[122,524,525],{},"pg_basebackup"," plus continuous WAL archiving to an S3-compatible bucket (Cloudflare R2, Backblaze B2, Wasabi, or S3 itself). pgBackRest does this and validates integrity.",[11,528,529,532],{},[28,530,531],{},"Hot standby replica via streaming replication."," A second server receiving the WAL in real time, ready to be promoted if the primary falls. Bonus: you use that same server for heavy read queries, offloading the primary.",[11,534,535,542],{},[28,536,537,538,541],{},"Monitoring with ",[122,539,540],{},"postgres_exporter"," + Prometheus + Grafana",", or an equivalent plugin from the orchestrator you use. You want to see: active connections, cache ratio, transaction rate, replication lag, disk space, slow queries. Without this, you're driving with your eyes closed.",[11,544,545,548],{},[28,546,547],{},"Automated monthly restore test."," Cron that picks the most recent backup, restores it on a temporary server, validates that some tables have rows. If that fails, alert the team. Backup that's never been restored is placebo. We've seen teams lose a whole week of data because the \"backup\" had been corrupted for three months and no one tested.",[18,550,552],{"id":551},"the-five-mistakes-that-break-self-hosted-postgres","The five mistakes that break self-hosted Postgres",[11,554,555],{},"They've been the same five for fifteen years. They don't innovate.",[11,557,558,561],{},[28,559,560],{},"Not testing restore."," We repeat because it's the most common item. Backup that's never been restored isn't backup, it's a file. Automated monthly restore is the civilized minimum.",[11,563,564,573,574,576,577,580,581,583],{},[28,565,566,567,569,570,572],{},"Keeping ",[122,568,466],{}," and ",[122,571,470],{}," at default."," Postgres's default is designed to run on a small server without assuming anything. In production, ",[122,575,466],{}," should be 25% of RAM, ",[122,578,579],{},"effective_cache_size"," 50–75%, ",[122,582,470],{}," calculated per simultaneous connection. Without this, you have 64 MB of cache on a server with 16 GB of RAM and performance is left on the table.",[11,585,586,589,590,593],{},[28,587,588],{},"Not monitoring slow queries."," A poorly written query by a distracted developer can lock the entire database. ",[122,591,592],{},"pg_stat_statements"," enabled, alert for any query going over 500 ms in production. Without this, you discover the problem when the customer opens a ticket.",[11,595,596,599,600,603],{},[28,597,598],{},"Disk shared with the operating system."," System log fills, the database's ",[122,601,602],{},"\u002Fvar"," shares the same volume, and the database stops accepting writes. Postgres has to be on a dedicated volume. NVMe if possible.",[11,605,606,609],{},[28,607,608],{},"A single server without replica."," Server falls — and it falls, sooner or later, hardware fails — and you're with one to three hours of downtime restoring from backup. Synchronous replica on another server reduces that to seconds.",[18,611,613],{"id":612},"postgres-on-an-orchestrator-like-heroctl","Postgres on an orchestrator like HeroCtl",[11,615,616],{},"This is where operational complexity drops. Not because Postgres got simpler — it's still complex — but because the orchestrator absorbs the plumbing part you'd normally write by hand.",[11,618,619,622,623,626,627,630],{},[28,620,621],{},"Postgres as a cluster task."," The service description is a configuration file of about thirty lines: official Postgres image, named volume for data, environment variables for credentials, reserved CPU and memory, restart policy. No ",[122,624,625],{},"systemd unit",", no ",[122,628,629],{},"apt install",", no manual firewall.",[11,632,633,636],{},[28,634,635],{},"Persistence via replicated named volume."," You say \"this volume is replicated between two servers\", and the orchestrator ensures the data exists on both. If the server running Postgres falls, the cluster reschedules on the second server with data already present. Recovery time in seconds, not hours.",[11,638,639,642],{},[28,640,641],{},"Integrated automatic backup"," in the Business plan: continuous WAL archiving to S3-compatible object storage, weekly snapshot, configurable retention. The same RDS feature, no check to AWS.",[11,644,645,648],{},[28,646,647],{},"Read replica as additional task."," You describe a second service pointing to the first as upstream replication. Five extra lines in the manifest. No console, no clicks, no manual step.",[11,650,651,654,655,657],{},[28,652,653],{},"Built-in metrics."," The orchestrator is already collecting CPU, memory, IO from each container. Adding ",[122,656,540],{}," is one more fifteen-line task. No assembling separate Prometheus, no provisioning Grafana, no popping another server.",[11,659,660,663],{},[28,661,662],{},"Automatic failover"," if the coordinating server falls: the cluster elects another coordinator in around seven seconds and continues scheduling. Postgres itself comes back on the remaining servers right after.",[11,665,666],{},"The full description of a Postgres with replica + backup + metrics on HeroCtl is around one hundred lines. In Kubernetes, the equivalent is an external operator (CloudNativePG or Zalando) plus 300 lines of manifest, plus a separate monitoring stack, plus cert-manager for internal TLS between nodes. For the team of five, the difference is between an afternoon and a sprint.",[18,668,670],{"id":669},"comparison-table","Comparison table",[132,672,673,698],{},[135,674,675],{},[138,676,677,680,683,686,689,692,695],{},[141,678,679],{},"Criterion",[141,681,682],{},"RDS São Paulo",[141,684,685],{},"Cloud SQL",[141,687,688],{},"Supabase",[141,690,691],{},"Neon",[141,693,694],{},"Simple Postgres VPS",[141,696,697],{},"Postgres on HeroCtl",[151,699,700,723,743,761,780,799,819,839,858,877,898,920],{},[138,701,702,705,708,711,714,717,720],{},[156,703,704],{},"Minimum cost (50 GB medium)",[156,706,707],{},"R$1,400\u002Fmo",[156,709,710],{},"R$1,300\u002Fmo",[156,712,713],{},"R$125\u002Fmo (Pro)",[156,715,716],{},"R$95\u002Fmo (Launch)",[156,718,719],{},"R$240\u002Fmo",[156,721,722],{},"R$245\u002Fmo",[138,724,725,728,731,733,735,737,740],{},[156,726,727],{},"Automatic backup",[156,729,730],{},"yes",[156,732,730],{},[156,734,730],{},[156,736,730],{},[156,738,739],{},"you configure",[156,741,742],{},"yes (Business)",[138,744,745,748,750,752,755,757,759],{},[156,746,747],{},"Point-in-time recovery",[156,749,730],{},[156,751,730],{},[156,753,754],{},"yes (Pro)",[156,756,730],{},[156,758,739],{},[156,760,742],{},[138,762,763,766,769,771,774,776,778],{},[156,764,765],{},"Real high availability",[156,767,768],{},"yes (Multi-AZ paid)",[156,770,730],{},[156,772,773],{},"partial",[156,775,730],{},[156,777,739],{},[156,779,730],{},[138,781,782,785,788,790,792,794,797],{},[156,783,784],{},"Custom extensions",[156,786,787],{},"restricted",[156,789,787],{},[156,791,787],{},[156,793,787],{},[156,795,796],{},"total",[156,798,796],{},[138,800,801,804,807,809,812,814,817],{},[156,802,803],{},"Lock-in",[156,805,806],{},"high",[156,808,806],{},[156,810,811],{},"medium",[156,813,811],{},[156,815,816],{},"none",[156,818,816],{},[138,820,821,824,827,829,832,834,837],{},[156,822,823],{},"Exit migration",[156,825,826],{},"weeks",[156,828,826],{},[156,830,831],{},"days",[156,833,831],{},[156,835,836],{},"hours",[156,838,836],{},[138,840,841,844,846,848,850,852,855],{},[156,842,843],{},"Included monitoring",[156,845,773],{},[156,847,730],{},[156,849,730],{},[156,851,730],{},[156,853,854],{},"you assemble",[156,856,857],{},"built-in",[138,859,860,863,865,867,869,871,874],{},[156,861,862],{},"Minimum expertise",[156,864,816],{},[156,866,816],{},[156,868,816],{},[156,870,816],{},[156,872,873],{},"senior",[156,875,876],{},"mid-level",[138,878,879,882,885,887,890,893,896],{},[156,880,881],{},"App↔db latency",[156,883,884],{},"1–4 ms",[156,886,884],{},[156,888,889],{},"5–30 ms",[156,891,892],{},"10–50 ms",[156,894,895],{},"0.3 ms",[156,897,895],{},[138,899,900,903,906,908,911,914,917],{},[156,901,902],{},"Ideal range",[156,904,905],{},"any",[156,907,905],{},[156,909,910],{},"up to 50 GB",[156,912,913],{},"up to 100 GB",[156,915,916],{},"indie",[156,918,919],{},"startup to mid-size",[138,921,922,925,927,929,931,933,936],{},[156,923,924],{},"LGPD compliance via vendor",[156,926,730],{},[156,928,730],{},[156,930,773],{},[156,932,773],{},[156,934,935],{},"you document",[156,937,935],{},[11,939,940],{},"No column wins at everything. Each is a coherent set of tradeoffs. Anyone trying to sell a column as \"the best\" is selling.",[18,942,944],{"id":943},"honest-decision-by-profile","Honest decision by profile",[11,946,947,950],{},[28,948,949],{},"MVP up to 10 GB and up to a hundred connections\u002Fsec."," Postgres as a container alongside the application, on a single VPS. Daily backup to S3-compatible object storage. Total cost, database and all, in the R$10\u002Fmonth range above what you already pay for the VPS. At some point you migrate — and migrating with 10 GB is a Sunday night, not a project. Start simple.",[11,952,953,956],{},[28,954,955],{},"Indie hacker between 10 and 100 GB."," Postgres on dedicated VPS, async replica on a second VPS, hourly backup to S3-compatible object (Cloudflare R2 or Backblaze B2 costs cents). Something between R$120 and R$200 per month total. If you have time to dedicate, this is the point where self-hosted pays off a lot.",[11,958,959,962],{},[28,960,961],{},"Early startup between 100 and 500 GB."," This is where the decision really lies. Evaluate RDS São Paulo on the LGPD compliance argument (AWS already has the datacenter certifications) — it'll come out in the R$1.5 to R$3k per month range. Or evaluate Postgres in a cluster managed by the orchestrator, on three dedicated VPSes, in the R$400 per month range — but it requires real operational discipline. It's not \"self-hosted made easy\". It's self-hosted with the orchestrator absorbing the plumbing part.",[11,964,965,968],{},[28,966,967],{},"Heavy compliance or Enterprise."," Managed makes sense when the audit framework asks for a vendor with specific certification. But read the contract — some RDS regions in Brazil still don't have all the certifications (HIPAA, FedRAMP, PCI level 1) that the American region has. If your auditor asks for a specific certificate, confirm the region has it before signing.",[18,970,972],{"id":971},"questions-inexperienced-teams-ask","Questions inexperienced teams ask",[11,974,975,978,979,981],{},[28,976,977],{},"Can I start self-hosted and migrate to RDS later?"," You can, and it's a valid strategy. Postgres is Postgres. You do ",[122,980,518],{}," of the base, restore to RDS, adjust the application endpoint, decommission the old server. Up to 50 GB, it's an operation of a few hours with a short window. The opposite path (leaving RDS for self-hosted) also works, but tools like AWS DMS make ingress easier than egress.",[11,983,984,987,988,990],{},[28,985,986],{},"Is RDS São Paulo reliable?"," The ",[122,989,124],{}," region is one of the oldest AWS regions outside the United States, operating since 2011, and has three independent availability zones. In global AWS incidents, São Paulo usually gets caught up. In regional incidents, it falls alone — which has happened twice in the last five years for a few hours. Reliable enough for production, not reliable enough to skip a plan B.",[11,992,993,999,1000,1002,1003,1005],{},[28,994,995,996,998],{},"Does backup with ",[122,997,518],{}," in cron solve it?"," It solves for MVP, doesn't solve for serious production. ",[122,1001,518],{}," is a logical dump — doesn't preserve exact state, loses on restore time (slow for large bases), and doesn't allow recovery to minute X. The right combination is weekly physical ",[122,1004,525],{}," plus continuous WAL archiving. Tool: pgBackRest.",[11,1007,1008,1011,1012,1014],{},[28,1009,1010],{},"When is it worth buying advanced Performance Insights?"," When you're on RDS, have more than five engineers touching the schema, and need to track \"who ran this query?\". On small teams, native ",[122,1013,592],{}," already delivers 80% of the value — turn it on first and see if you need more.",[11,1016,1017,1020],{},[28,1018,1019],{},"And Supabase, Neon, Crunchy?"," They're different products on top of Postgres. Supabase is Postgres + auth + generated REST API + file storage — good for a project that needs all that integrated, bad for those wanting just a database. Neon separates storage and compute, sleeps when idle, great for staging environment and spiky workload. Crunchy is pure Postgres with enterprise focus and Kubernetes operator. The three have reasonable free tiers for MVP — worth testing before closing with RDS.",[11,1022,1023,1026,1027,1030],{},[28,1024,1025],{},"How do I do real HA without RDS Multi-AZ?"," Synchronous replica on a second server (",[122,1028,1029],{},"synchronous_standby_names"," configured) ensures each commit was written to both before returning OK to the application. Failover via Patroni, or via orchestrator like HeroCtl. The sensitive point is split-brain: the replica can't promote itself without external confirmation. Patroni solves it with etcd as arbiter. HeroCtl solves it with the distributed control plane itself acting as arbiter — without setting up an extra service.",[11,1032,1033,1036],{},[28,1034,1035],{},"Does HeroCtl run heavy Postgres in production for real?"," It does. The public cluster of the documentation itself serves this blog through a stack that includes a self-hosted Postgres as a cluster task, with replica and backup. For workloads above 500 GB or with IOPS requirements in the 50k range, we recommend evaluating managed — not because the orchestrator can't handle it, but because AWS's provisioned IOPS and I\u002FO control in that range start to make real operational difference.",[18,1038,1040],{"id":1039},"closing","Closing",[11,1042,1043],{},"There's no single answer to \"managed or self-hosted Postgres\". There's your spreadsheet. If you opened this post looking for confirmation, what you found was numbers — use them.",[11,1045,1046],{},"For profiles where self-hosted pays off but operation scares you, HeroCtl is the layer that reduces friction. Backup, replica, monitoring, and failover described in a hundred lines of configuration, running on your cluster, no check to vendor, no lock-in.",[11,1048,1049],{},"Install with:",[1051,1052,1057],"pre",{"className":1053,"code":1054,"language":1055,"meta":1056,"style":1056},"language-bash shiki shiki-themes github-dark-default","curl -sSL get.heroctl.com\u002Finstall.sh | sh\n","bash","",[122,1058,1059],{"__ignoreMap":1056},[1060,1061,1064,1068,1072,1076,1080],"span",{"class":1062,"line":1063},"line",1,[1060,1065,1067],{"class":1066},"sQhOw","curl",[1060,1069,1071],{"class":1070},"sFSAA"," -sSL",[1060,1073,1075],{"class":1074},"s9uIt"," get.heroctl.com\u002Finstall.sh",[1060,1077,1079],{"class":1078},"suJrU"," |",[1060,1081,1082],{"class":1066}," sh\n",[11,1084,1085,1086,1091,1092,1096],{},"For more on the total cost of hosting SaaS in Brazil in 2026, read ",[1087,1088,1090],"a",{"href":1089},"\u002Fen\u002Fblog\u002Fhow-much-to-host-a-brazilian-saas-2026","how much it costs to host a Brazilian SaaS",". For the practical transition from Docker Compose to a cluster with real high availability, read ",[1087,1093,1095],{"href":1094},"\u002Fen\u002Fblog\u002Fdocker-deploy-production-compose-to-cluster","Docker deploy in production, from Compose to cluster",".",[11,1098,1099],{},"The honest math is the one that fits your spreadsheet. Run the numbers before deciding.",[1101,1102,1103],"style",{},"html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":1056,"searchDepth":1105,"depth":1105,"links":1106},2,[1107,1108,1109,1115,1116,1117,1118,1119,1120,1121,1122],{"id":20,"depth":1105,"text":21},{"id":73,"depth":1105,"text":74},{"id":116,"depth":1105,"text":117,"children":1110},[1111,1113,1114],{"id":129,"depth":1112,"text":130},3,{"id":224,"depth":1112,"text":225},{"id":328,"depth":1112,"text":329},{"id":453,"depth":1105,"text":454},{"id":489,"depth":1105,"text":490},{"id":551,"depth":1105,"text":552},{"id":612,"depth":1105,"text":613},{"id":669,"depth":1105,"text":670},{"id":943,"depth":1105,"text":944},{"id":971,"depth":1105,"text":972},{"id":1039,"depth":1105,"text":1040},"engineering",null,"2026-04-15","RDS starts at US$15\u002Fmonth — ends at US$500. Self-hosting starts at $0 — ends waking you up at 3 a.m. How to decide between the two without lying to yourself.",false,"md",{},true,"\u002Fen\u002Fblog\u002Fpostgres-in-production-managed-vs-self-hosted","14 min",{"title":5,"description":1126},{"loc":1131},"en\u002Fblog\u002Fpostgres-in-production-managed-vs-self-hosted",[1137,1138,1139,1140,1123],"postgres","database","rds","self-hosted","3XZJAM1qeoTtGvzK2RyJe9zIZBX90xtG6dEwdjX6w-s",[1143,1149],{"title":1144,"path":1145,"stem":1146,"description":1147,"date":1148,"category":1123,"children":-1},"Observability without Datadog: the alternative stack that fits the Brazilian budget","\u002Fen\u002Fblog\u002Fobservability-without-datadog-startup-stack","en\u002Fblog\u002Fobservability-without-datadog-startup-stack","Datadog charges US$15-31\u002Fhost\u002Fmonth. For a startup with 5 servers, that's R$1k\u002Fmonth just on monitoring. The self-hosted stack reaches the same place for R$50.","2026-04-08",{"title":1150,"path":1151,"stem":1152,"description":1153,"date":1154,"category":1123,"children":-1},"Redis (and Valkey) in production: managed vs self-hosted in 2026","\u002Fen\u002Fblog\u002Fredis-in-production-managed-vs-self-hosted","en\u002Fblog\u002Fredis-in-production-managed-vs-self-hosted","Redis changed its license in 2024, Valkey was born as an OSS fork, Dragonfly hits benchmarks. In 2026, choosing cache is no longer choosing Redis — it's choosing between 4 products. Honest analysis with costs.","2026-05-20",1777362215178]