Contents
Why Major Upgrades Get Postponed
Every PostgreSQL major version brings performance improvements, better tooling and security fixes, and every team I know postpones the upgrade. The traditional path on Amazon RDS, an in-place major version upgrade, takes the database offline for the duration of pg_upgrade plus pre- and post-upgrade checks. On a busy system that means a maintenance window, a nervous weekend and a rollback plan that amounts to "restore the snapshot and lose everything written since".
The pressure to upgrade has also risen. Older major versions eventually leave standard support on RDS and move into paid Extended Support, so deferring the upgrade now has a direct cost as well as a risk.
RDS Blue/Green Deployments, generally available for RDS for PostgreSQL since October 2023, change the shape of the problem. This post is general advice from planning upgrades of this kind; the details apply to any team running RDS for PostgreSQL.
How It Works
A blue/green deployment creates a copy of your production environment (blue) as a staging environment (green), keeps green in sync with blue, and then switches over by swapping endpoints.
For a PostgreSQL major version upgrade the mechanics are:
- RDS creates the green instance from a snapshot of blue, then upgrades green to the target major version.
- RDS uses PostgreSQL logical replication to stream changes from blue to green. Physical replication can't cross major versions, which is why logical replication is used here.
- You test against the green endpoint while production continues on blue.
- At switchover, RDS stops writes on blue, waits for green to catch up, synchronises sequences, then renames the instances so green takes over blue's endpoint names. Applications reconnect to the same hostnames.
- The old blue instances are kept, renamed with an
-old1suffix, for you to inspect or delete.
aws rds create-blue-green-deployment \
--blue-green-deployment-name orders-pg-upgrade \
--source arn:aws:rds:eu-west-2:123456789012:db:orders-prod \
--target-engine-version 16.4 \
--target-db-parameter-group-name orders-pg16The target parameter group must belong to the new major version's family, so create and review it before you start rather than discovering missing settings after switchover.
Prerequisites and Limitations
This is where most of the work is. Logical replication has real gaps, and a blue/green deployment inherits them.
| Area | Limitation | What to do |
|---|---|---|
| Logical replication setting | rds.logical_replication must be enabled on blue; it's a static parameter |
Change the parameter group and reboot in a quiet period well before the upgrade |
| Replica identity | UPDATE and DELETE on tables without a primary key or replica identity cause replication errors |
Add primary keys, or set REPLICA IDENTITY FULL on the affected tables as a last resort |
| DDL | Schema changes are not replicated | Freeze migrations from creation of green until after switchover |
| Sequences | Not replicated continuously; RDS synchronises them during switchover | Expect switchover to take longer with many sequences |
| Large objects | Data in pg_largeobject isn't replicated |
Check for large objects; migrate them to bytea or object storage first |
| Materialised views | Refreshes aren't replicated | Refresh on green after switchover |
| Extensions | Must be supported on the target version; some behave differently across versions | Check every installed extension against the target version and upgrade them on green |
| Write load | A long-lived replication slot on blue retains WAL if green falls behind | Monitor replica lag and free storage on blue throughout |
Two queries I'd run before starting. First, tables that will break replication of updates and deletes:
SELECT n.nspname AS schema_name, c.relname AS table_name
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
AND (
c.relreplident = 'n'
OR (
c.relreplident = 'd'
AND NOT EXISTS (
SELECT 1 FROM pg_index i
WHERE i.indrelid = c.oid AND i.indisprimary
)
)
);Second, whether you use large objects at all:
SELECT count(*) FROM pg_largeobject_metadata;Rehearse It
Never make production your first blue/green deployment. Restore a recent snapshot into a separate environment, create a blue/green deployment from it and switch over while a load generator writes to it. A rehearsal answers the questions that matter:
- How long does green take to create, upgrade and catch up?
- Does the application work on the new version? Run the full test suite and key queries against the green endpoint, and compare query plans for your most important queries, because planner changes between major versions can cause regressions.
- How does your application behave during the switchover? Watch connection pools, retries and error rates.
- How long does the switchover take with your number of sequences and your write load?
Rehearsal also flushes out things like an ORM migration that runs on deploy and would break the DDL freeze.
Switchover Guardrails and Timings
Switchover has built-in guardrails: RDS checks that both environments are healthy and that replication is caught up, and if the switchover can't complete within the timeout it rolls back and leaves both environments unchanged. The timeout defaults to 300 seconds and can be set from 30 seconds to one hour.
aws rds switchover-blue-green-deployment \
--blue-green-deployment-identifier bgd-EXAMPLE1234567 \
--switchover-timeout 120In practice, switchover is typically under a minute of write unavailability, but that depends on your load. My own guardrails around it:
- Pick a low-traffic window. Blue/green reduces downtime; it doesn't make it zero. Avoid trading peaks entirely.
- Check replica lag first. Switch only when lag is close to zero; long-running transactions on blue can delay the switchover.
- Stop non-essential writers. Pause batch jobs and queue consumers briefly. With SQS in front of background work, messages simply wait.
- Make clients resilient. Short DNS caching, connection pools that recycle broken connections, and retries on idempotent operations.
- Run
ANALYZEon green after switchover. Planner statistics aren't carried across a major upgrade, and missing statistics are a common cause of post-upgrade slowness.
Rollback Thinking
Blue/green gives you an easy rollback before switchover: delete the green environment and nothing has changed. After switchover, it's different. Replication doesn't reverse, so writes made on the new version exist only there. The old instance is a point-in-time copy that is immediately out of date.
Be honest about this in the plan. Realistic options after switchover are to fix forward on the new version, or accept data loss by reverting to the old instance, or set up reverse logical replication yourself in advance, which is possible but adds complexity. For most teams, thorough rehearsal plus fix-forward is the right choice. Keep the old instance for a few days anyway, for comparison and forensics.
Alternatives
| Approach | Downtime | Effort | When I'd use it |
|---|---|---|---|
| In-place major version upgrade | Minutes to much longer, depending on database size and objects | Low | Small databases, or where a maintenance window is acceptable |
Manual pg_upgrade to a new instance (self-managed PostgreSQL) |
Similar to in-place | Medium | Not available as such on RDS; relevant if you run PostgreSQL yourself |
| RDS Blue/Green Deployments | Typically under a minute | Medium | Most production RDS for PostgreSQL upgrades |
| AWS DMS or native logical replication, managed yourself | Seconds to minutes at cutover | High | Cross-account or cross-region moves, or combining upgrade with other changes |
The Takeaway
RDS Blue/Green Deployments make major PostgreSQL upgrades a rehearsed, low-downtime operation rather than a weekend outage, but only if you respect logical replication's limits: primary keys, a DDL freeze, large objects and extensions. Rehearse on a restored copy, set tight switchover guardrails and decide your rollback stance before you start. Done that way, upgrades become routine enough that you stop falling behind.
