Skip to main content

Railway's One-Click Postgres Upgrades Land as Postgres 14's Clock Runs Out: the Button, the CNPG Runbook, and the 6x Cost Gap

9 min readDora NodaDora Noda
Share
On this page

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 — :latest and 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, aclitem columns (both pre-16 concerns), open prepared transactions, logical replication slots, md5 password 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_upgrade in 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 clickWhat it automatesThe CNPG manual equivalent
Preflight report8 read-only compatibility checks against the live DBHand-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 backupAutomatic backup before anything movesScheduled Barman/object-store backup plus a test restore — the backup only counts once you have proved it restores
pg_upgrade orchestrationStop → upgrade → redeploy as one tracked jobImage 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 backupAutomatic restore point on the new majorManual backup trigger once the new major is serving, before reopening writes
HA handlingFailover paused, primary upgraded, replicas rebuiltSame sequence driven by you: confirm failover is held, verify primary on the new major, watch each replica rebuild, re-enable failover
Revert bannerOne-click restore of the pre-upgrade backupRestore 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.

  1. 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 for md5 auth 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 running ALTER EXTENSION … UPDATE first.
  2. 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.
  3. 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.
  4. 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.
  5. Post-upgrade. Confirm serving, trigger the post-upgrade backup, run ANALYZE across the databases (planner statistics do not survive pg_upgrade optimally), update extensions, and re-create logical replication slots and consumers.
  6. 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 comparingRailway (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 windowMetered storageObject-storage bucket at cost
Ops labor per major upgrade (1–2x/year)Zero — the buttonHalf 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.
  • md5 auth migration is still yours. The preflight flags roles on md5; moving them to SCRAM happens before you click, by hand.
  • Downtime is minutes, not zero. pg_upgrade in 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.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex