Railway picked a pointed week to ship one-click Postgres major version upgrades. Its September 11 changelog turns a major-version bump into a dashboard button — preflight checks, backups, the pg_upgrade run itself, and a rollback option in one flow. Meanwhile the community clock is ticking: PostgreSQL 14 reaches end of life on November 12, 2026, and PostgreSQL 19 is expected to go GA later this month.
Everybody still on 14 through 17 has upgrade planning to do within weeks, not quarters.
Here is the accounting up front. A comparable 2 vCPU / 4 GB / 50 GB Postgres costs ≈ $87.50/month on Railway's meter against ≈ €10–12/month (≈ $11–13) on a Hetzner-hosted CloudNativePG cluster — roughly a 6–7x gap that narrows but never closes as you size up. What the extra dollars buy is concrete: a six-job upgrade runbook — preflight compatibility checks, a verified pre-upgrade backup, pg_upgrade orchestration, a post-upgrade backup, HA replica handling, and a revert path — compressed into one click. This post maps every click to its manual equivalent, gives you the CNPG runbook to match it, and prices both sides at two sizes.
What Railway actually shipped
Changelog #0307 adds a Database → Config → Major Version Upgrade flow for Postgres services. The fact box:
- Scope: source majors 14 through 17, upgrading to any newer major Railway publishes. Official Railway images only (
postgres-ssl, or Patroni-based Postgres HA) with a pinned version tag —:latestand custom images are out. - Preflight: a read-only compatibility report run against the live database before anything moves. It checks
reg*catalog-OID column types,aclitemcolumns (both pre-16 concerns), open prepared transactions, logical replication slots,md5password auth, event triggers, extension availability versus the target image, and data size. Blockers stop the flow; warnings do not. - The upgrade: Railway takes a backup, stops the database, runs
pg_upgradein place, redeploys on the new major's image, then takes a second backup. The database is unavailable for "a few minutes depending on data size." - HA handling: on a Postgres HA cluster, failover is paused, the primary is upgraded, and every replica is rebuilt from it on the new major before failover resumes. The whole cluster moves together.
- Rollback: a limited post-upgrade window offers one-click revert to the pre-upgrade backup. Reverting discards every write made after the upgrade — and if the upgrade itself fails, the same restore fires automatically.
Same changelog, for context: a São Paulo CDN region, email forwarding for Railway domains, and Claude Max subscriptions for community Conductors. But the Postgres button is the piece with a direct self-hosting equivalent — and it lands one month after August's automatic CVE patching and MySQL/Redis HA pushed the same managed-data moat deeper.
The anatomy table: every click mapped to a manual step
Nothing in the button is magic. Each automated step corresponds to one job a CloudNativePG operator does by hand. CNPG has shipped declarative offline in-place major upgrades since 1.26 — bump the image (directly via spec.imageName or through an Image Catalog), and the operator shuts the cluster down, validates conditions with a job, and runs pg_upgrade. Image Catalogs (GA in 1.29) add the extension-compatibility gating. Here is the full mapping:
| Railway click | What it automates | The CNPG manual equivalent |
|---|---|---|
| Preflight report | 8 read-only compatibility checks against the live DB | Hand-run SQL per check: SELECT * FROM pg_prepared_xacts, extension inventory vs target image, md5 role audit, replication-slot listing — no bundled report; you assemble it |
| Pre-upgrade backup | Automatic backup before anything moves | Scheduled Barman/object-store backup plus a test restore — the backup only counts once you have proved it restores |
pg_upgrade orchestration | Stop → upgrade → redeploy as one tracked job | Image bump in the Cluster manifest (or catalog version pin), then monitor the operator's validation + upgrade jobs; downtime is the same shape — cluster stopped, minutes-scale |
| Post-upgrade backup | Automatic restore point on the new major | Manual backup trigger once the new major is serving, before reopening writes |
| HA handling | Failover paused, primary upgraded, replicas rebuilt | Same sequence driven by you: confirm failover is held, verify primary on the new major, watch each replica rebuild, re-enable failover |
| Revert banner | One-click restore of the pre-upgrade backup | Restore from backup onto a new cluster — CNPG has no in-place recovery on the existing cluster, so rollback means bootstrapping fresh and repointing; same data-loss rule (post-upgrade writes are gone either way) |
The honest summary: the button compresses six jobs into one, but five of the six exist on both sides. The genuinely asymmetric row is the last one — Railway's revert is a banner; yours is a restore-and-repoint procedure you should have rehearsed before upgrade day.
The worked CNPG runbook
If you run tenant Postgres on CloudNativePG, this is the runbook that matches the button step for step. Do it once against a staging cluster cloned from production backup before touching the real one.
- Preflight. Query
pg_prepared_xacts(must be empty), list logical replication slots (consumers re-create them post-upgrade — slots are not carried over), audit roles formd5auth and move them to SCRAM, review event triggers, and diff installed extensions against the target image: missing from the image is a blocker, behind the image version means runningALTER EXTENSION … UPDATEfirst. - Backup and prove it. Take a fresh on-demand backup, then restore it somewhere disposable and run a smoke query. An untested backup is a hope, not a restore point.
- Pin the target declaratively. Point the Cluster at the new major via your Image Catalog pin (preferred — the catalog carries extension versions with the image) or
spec.imageName. Commit it to git like any other fleet change; the manifest is the audit trail Railway's progress panel gives you for free. - Watch the jobs, not just the pods. The operator runs a validation job before
pg_upgrade. If validation fails, fix the flagged condition and re-apply — this is your preflight re-run button. - Post-upgrade. Confirm serving, trigger the post-upgrade backup, run
ANALYZEacross the databases (planner statistics do not survivepg_upgradeoptimally), update extensions, and re-create logical replication slots and consumers. - Know your revert before you need it. Rollback is a recovery onto a new cluster from the pre-upgrade backup, then repointing connection strings. Practice the repoint — DNS or service-object flip — ahead of time, because the failure case is the wrong moment to discover your app hardcodes a hostname.
If "minutes of stopped database" is unacceptable for a given tenant, the answer on both platforms is the same escape hatch EDB documents: native logical replication for a near-zero-cutover migration instead of an in-place upgrade. Railway's button does not offer it either — both sides go offline for the in-place path.
The cost math, at two sizes
Pricing sources: Railway's Postgres at 2 vCPU / 4 GB / 50 GB runs ≈ $87.50/month in current third-party meter comparisons, with block storage at $15/month per 100 GB. Hetzner's current cloud list puts a CX33 (4 vCPU / 8 GB / 80 GB) at roughly €6.50–9/month and extra volumes near €0.50 per 10 GB. Object storage for Barman backups is single-digit euros at these sizes. The comparison:
| What you are comparing | Railway (metered) | Hetzner + CNPG (flat) |
|---|---|---|
| Small: 2 vCPU / 4 GB / 50 GB, standalone | ≈ $87.50/month | ≈ €10–12/month (CX33 share + volume + backup bucket) |
| Mid: 4 vCPU / 16 GB / 200 GB, HA pair | ≈ $250–350/month (primary + replica meter independently, plus storage) | ≈ €35–50/month (two dedicated boxes + volumes + backup bucket) |
| Backup retention beyond the bundled window | Metered storage | Object-storage bucket at cost |
| Ops labor per major upgrade (1–2x/year) | Zero — the button | Half a day: rehearsal restore, upgrade window, post-checks |
Two honest adjustments before you quote the ratio. First, the 6–7x hardware gap is real but the labor row is not zero-valued: two engineers spending half a day per upgrade, twice a year, prices the button at a few hundred dollars a year in time — still far below the meter delta at any size that needs HA, but not free. Second, the button's own fine print applies to both sides: downtime is minutes either way, and reverting discards post-upgrade writes either way. You are not buying zero-downtime or lossless rollback; you are buying never having to rehearse the runbook.
What the button does not do
Four limits survive the click, and they are the same four that bound the CNPG runbook — worth stating because "one-click" reads as "zero-thought":
- Logical replication slots are not carried over. Consumers must re-create them after the upgrade. If your CDC pipeline feeds a warehouse, plan that cutover explicitly.
md5auth migration is still yours. The preflight flags roles onmd5; moving them to SCRAM happens before you click, by hand.- Downtime is minutes, not zero.
pg_upgradein place means a stopped database for the duration. Near-zero cutover requires the logical-replication path, which neither the button nor the CNPG in-place job provides. - The rollback window is limited and lossy. Revert restores the pre-upgrade backup; everything written since is gone. Long after the window closes, your only rewind is your own backup retention — which, on the self-hosted side, you control, and on the metered side, you rent.
None of this diminishes the button. It is the correct shape for the product: preflight plus backups plus tracked pg_upgrade plus a rehearsed-looking revert covers ~90% of what goes wrong in real major upgrades. The remaining 10% — slots, auth, cutover strategy, retention policy — is genuinely your architecture, and no button can click it for you.
The takeaway for self-hosters
Upgrade season is here whether you have the button or not: PG14 goes EOL November 12, PG19 lands within weeks, and every fleet on 14 through 17 gets to do this dance. Railway's price for skipping the rehearsal is the meter; the self-hosted price is the runbook above plus half a day. Pick the one denominated in the currency you have — dollars or attention — and either way, test-restore the backup before upgrade day.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Managed databases are an explicit non-goal: if your app needs Postgres, the honest self-hosted path is CNPG on hardware you control, runbook included. Star the repo on GitHub or deploy your first app today.



