6 min read
PostgreSQL 14’s end of life is a compatibility-planning problem
The date is a trigger, not a migration plan
PostgreSQL 14 is scheduled to reach end of life on November 12, 2026, according to the PostgreSQL versioning policy. I would treat that date as a reason to start making decisions now, not as a date by which every database must follow the same upgrade procedure.
A major-version change is not complete when the new server starts. The application still needs to behave correctly; extensions need to work; replication needs to resume in the intended direction; backups need to remain restorable; and the chosen upgrade path needs to fit the workload’s downtime and recovery constraints. Those connections are where planning gets expensive. A server that starts successfully is evidence that one step worked, not proof that the system is compatible.
I would begin by mapping those dependencies for each workload, rather than treating “PostgreSQL 14” as a single item on an infrastructure inventory. Two databases on the same major version can have different extensions, clients, replication arrangements, recovery requirements, and tolerance for downtime. They may need different target versions and different migration paths. The cutoff is shared; the plan does not have to be.
Map the compatibility chain before picking a path
I’d make the first pass an inventory that answers practical questions, not just records server versions. Which application services connect to the database? Which driver versions and database features do they depend on? Which extensions are installed, and who provides packages compatible with the target server? Is replication physical, logical, or both? What backup format is in use, and has a restore been tested against the proposed destination? What downtime can the workload tolerate?
That inventory helps turn a vague upgrade into explicit checks. For application behavior, I would identify queries and features the application relies on, then test representative reads and writes against the candidate version. A successful connection or a green startup check does not exercise query semantics, migrations, scheduled tasks, or the paths an application runs under load. I would use the application’s real test suite where possible and add targeted checks where it leaves important behavior uncovered.
Extensions deserve their own line in the plan. I would compare the installed extension list with the packages and supported versions available for the target server, then check whether each extension needs a separate update step. PostgreSQL’s extension packaging documentation describes how an extension can provide update scripts that ALTER EXTENSION UPDATE runs. That mechanism does not mean every extension has a suitable update path for every target. I would confirm availability and test the actual update sequence on a restored copy rather than assume that an extension present on the old server will be ready on the new one.
Replication and recovery also belong in the compatibility map, not in a last-minute operations checklist. PostgreSQL documents a specific logical replication procedure for major-version upgrades; it is a procedure with prerequisites and steps, not a promise that an existing topology will transfer unchanged. For backups, I would distinguish logical dumps from file-level backups. The PostgreSQL SQL dump documentation notes that pg_dump output can generally be loaded into newer PostgreSQL versions, while file-level backups and continuous archiving are server-version-specific. Either way, I would test the restore path: a backup that has not been restored is an assumption, not a demonstrated recovery option.
Choose the path around the workload
I would choose the upgrade method only after understanding those dependencies and constraints. PostgreSQL’s pg_upgrade documentation explains that it can move data files to a later major version without the dump-and-restore process; it is not needed for minor-version upgrades. That can make it an appropriate option when the workload needs a direct major-version transition and its environment meets the method’s requirements. It does not remove the need to validate application behavior, extensions, replication, and recovery around that transition.
Logical replication can support a staged move, but it has its own coordination work. The official major-version logical replication upgrade procedure includes steps for upgrading nodes and refreshing publications. I would evaluate it where a workload benefits from separating data movement from the final cutover, then test the full sequence—including the point at which writes change direction. It is not a free way to avoid downtime or compatibility checks; it moves some of the work into topology, replication, and cutover planning.
Dump and restore is another path to consider when portability or a clean rebuild matters more than the time required to move and reload data. The SQL dump documentation describes the cross-version usefulness of logical dumps, but the practical cost depends on the workload and how long the restore and validation take. I would test that duration using a representative copy rather than assume it from a small development database.
The relevant choice is not “Which upgrade method is best?” It is “Which method can this workload execute, validate, and recover from within its constraints?” I would write down the expected cutover, the checks that let the operator proceed, and the conditions that mean stop or roll back. If the rollback plan depends on an old server continuing to accept writes after cutover, that dependency needs to be designed and tested—not discovered during the change.
Sequence the work; don’t force one fleet-wide move
I would sequence the migration as a set of workload decisions. First, classify databases by dependency and operational constraint: extensions, replication, restore method, application coupling, and acceptable interruption. Next, identify a target and a candidate upgrade path for each group. Then rehearse the path on a restored copy, checking application behavior and the operational steps together. Finally, schedule production moves in cohorts, leaving room to apply what the earlier moves teach before progressing to workloads with different constraints.
This is not an argument for delaying the decision until every detail is known. The date is close enough that unknowns should be made visible immediately: an extension with no confirmed target package, an untested restore, or a service with no representative test is a planning item with an owner, not a reason to assume compatibility. Nor would I make “move everything together” the default just because one shared deadline appears in a version policy. Workloads that can move independently should be able to do so; tightly coupled ones need an explicitly coordinated plan.
I would call a migration ready when the surrounding system has been exercised on the target version and the team knows what it will do if a check fails. The server starting is a necessary milestone. The evidence that applications, extensions, replication, and recovery still fit together is what makes the upgrade complete.
Drafted with AI assistance, reviewed and edited by Ali.