Deep dive
What "managed" actually buys
| Concern | Managed gives | Self-host must provide |
|---|---|---|
| Backups + PITR | Automatic, restore button | pgBackRest/WAL-G to object storage, monthly restore drill |
| Failover | Standby + DNS flip in 30-120 s | Patroni/repmgr, fencing, tested runbook |
| Upgrades | Minor versions automatic, majors assisted | Rolling upgrades, compatibility testing |
| Security | Patching, encryption at rest, IAM integration | Patch cadence, disk encryption, secret rotation |
| Scaling | Resize with a click (minutes of downtime or none) | Migration plan, replication to a bigger host |
| On-call | Provider's SRE team | Yours, 24/7 |
Decision table
| Situation | Choice | Why |
|---|---|---|
| < 5 engineers, product not proven | Managed for everything stateful | Time to market dominates; bill is small |
| Stateless app servers | Self-host on VMs or containers anywhere | No state, nothing to lose; managed premium buys little |
| Postgres < 1 TB, normal load | Managed (RDS, Cloud SQL, Azure Flexible, Neon, Crunchy) | Backups and failover are where self-hosting bites |
| Postgres > 5 TB or IOPS-heavy, steady | Self-host on NVMe bare metal with Patroni | Managed IOPS pricing explodes; local NVMe gives 10x IOPS |
| Kafka-like log at > 100 MB/s | Self-host (or Redpanda/WarpStream BYOC) | Managed per-partition and cross-AZ pricing grows linearly |
| Redis/Valkey cache, losing it is fine | Self-host, single node + replica | Cache is easy to run; a restart loses only warm data |
| Search (Elasticsearch/OpenSearch) | Managed until it hurts, then self-host | Clusters are fiddly; managed is pricey per GB |
| Object storage | Always managed (S3, R2, GCS, B2) | Durability of 11 nines is very hard to build yourself |
| Auth, email delivery, payments | Always buy | Security and deliverability are full-time jobs |
| Compliance-heavy (HIPAA, PCI) | Managed with attestations | Auditors accept provider reports |
Code
A TCO model that includes people; run it per component.
/// infra: $/month; eng_hours: ops hours per month; incidents priced as expected loss.
fn tco_month(infra: f64, eng_hours: f64, eng_rate: f64, incidents_per_year: f64, incident_cost: f64) -> f64 {
infra + eng_hours * eng_rate + incidents_per_year * incident_cost / 12.0
}
fn main() {
let managed = tco_month(1800.0, 4.0, 120.0, 0.0, 0.0); // RDS Multi-AZ, 2 TB
let self_host = tco_month(350.0, 20.0, 120.0, 1.0, 20_000.0); // 2 bare-metal boxes + backups
println!("{managed:.0} {self_host:.0}"); // 2280 4417 -> managed wins at this size
// at 10x data the managed infra line grows ~10x; self-host hours grow far less
}
Minimum self-host kit for Postgres (the part people skip):
# continuous WAL archive + nightly base backup to object storage
pgbackrest --stanza=main --type=full backup # cron nightly
pgbackrest --stanza=main --type=incr backup # cron hourly
# monthly restore drill on a throwaway host; alert if it fails
pgbackrest --stanza=main --delta --type=time --target="$(date -d '-1 hour' '+%F %T')" restore
Efficiency
- Cost: total cost of ownership = infrastructure + operations hours × rate + expected incident loss (the model in Code above). With its illustrative inputs the managed option costs 2,280 and the self-hosted one 4,417 per month; the inputs are examples, not measurements. Bound: engineer hours, not hardware.
- Levers:
- parallel backup and restore (
process-max) — shorter backup and restore windows, at some database load (pgBackRest configuration docs) — large Postgres - differential and incremental backups — less data per backup run (pgBackRest user guide) — nightly and hourly schedules
- managed for stateful, self-host for stateless — keeps ops hours on the parts where managed buys most (this page) — small teams
- open protocols (Postgres, S3, Kafka) — a later move costs a migration, not a rewrite (this page) — any managed choice
- re-run the model yearly and at 10x data — the answer flips with scale (this page) — growing bills
- parallel backup and restore (
- Naive → standard → state of the art:
- self-host everything with untested restores, or buy only proprietary managed APIs · hidden outage cost or lock-in
- managed for stateful, self-host stateless, monthly restore drill · operations hours stay low
- self-host the one service class above order of $10-30k/month on NVMe with scripted backups and failover · premium removed, hours bounded
Implementation notes
- Self-host on boring tech: Debian/Ubuntu LTS, systemd, one config management tool, the same Infrastructure as code you use for managed parts.
- Keep backups on a different provider than the primary (e.g. Hetzner servers backing up to R2 or B2).
- Managed but portable: prefer services that speak an open protocol (Postgres, Redis, S3, Kafka) so you can leave later.
- Re-run the decision yearly; the right answer flips as the bill grows.
Pitfalls
- Counting only hardware: self-hosting a database "for $100/month" without tested restores is a time bomb.
- Managed lock-in through proprietary APIs (DynamoDB, Firestore, Cosmos DB): leaving means a rewrite, not a migration.
- Managed services still need you: slow queries, schema design, connection limits and capacity planning stay yours.
- Hidden managed costs: IOPS, cross-AZ replica traffic, backup storage beyond the free size, per-request API fees.
- Self-hosted Kubernetes to run three services: the cluster becomes the main job.
Implementations
| name | lang | repo | install | verdict | licence | health | as_of | notes |
|---|---|---|---|---|---|---|---|---|
| pgBackRest | C | pgbackrest/pgbackrest | brew install pgbackrest | — | — | — | — | parallel, incremental backups and PITR |
| WAL-G | Go | wal-g/wal-g | brew install wal-g | — | — | — | — | archive and restore to object storage |
| Patroni | Python | patroni/patroni | pip install patroni | — | — | — | — | Postgres failover with etcd or Consul |
| CloudNativePG | Go | cloudnative-pg/cloudnative-pg | n/a (Kubernetes operator, see docs) | — | — | — | — | Postgres operator with backups and failover |
| Kamal | Ruby | basecamp/kamal | gem install kamal | — | — | — | — | deploy apps to own servers |
Sources
- David Heinemeier Hansson, Why we're leaving the cloud, 37signals/HEY blog, 2022. post
- Betsy Beyer et al., Site Reliability Engineering, O'Reilly, 2016. book
- Sarah Wang and Martin Casado, The Cost of Cloud, a Trillion Dollar Paradox, Andreessen Horowitz, 2021. post
- pgBackRest, Configuration docs and User Guide docs