PostgreSQL upgrades are usually postponed because the application is working, the database is stable, and nobody wants to introduce unnecessary risk.
That approach can become a problem when a PostgreSQL major version reaches the end of its supported life. PostgreSQL 14 is approaching that point, so teams still running PostgreSQL 14 should treat the upgrade as planned engineering work rather than waiting until the deadline is close.
For .NET applications, a PostgreSQL upgrade involves more than installing a newer database server. The application may depend on Npgsql, Entity Framework Core, database extensions, SQL behavior, indexes, stored procedures, connection settings, and deployment infrastructure.
This article walks through a practical approach for preparing a PostgreSQL 14 application for a major-version upgrade.
Why PostgreSQL 14 Upgrades Need Planning
A major PostgreSQL upgrade is different from a routine minor-version update.
Major releases can introduce changes in:
PostgreSQL 14 is scheduled to stop receiving fixes on November 12, 2026.
That date should be treated as a planning milestone. The goal is not to perform an emergency migration immediately before support ends. The goal is to have enough time to test, fix compatibility problems, rehearse the migration, and schedule production downtime if required.
Start With an Upgrade Inventory
Before choosing a target PostgreSQL version, understand what your current environment actually contains.
Create an inventory covering:
| Area | What to Check |
|---|
| PostgreSQL | Exact 14.x version |
| Database size | Total and largest databases |
| Tables | Largest and busiest tables |
| Extensions | Installed extensions and versions |
| Application | .NET and ORM versions |
| Driver | Npgsql version |
| SQL | Custom queries and database functions |
| Infrastructure | Containers, VMs, managed database services |
| Backups | Backup and restore process |
| Replication | Streaming/logical replication if used |
| Monitoring | Database and application monitoring |
You can begin with:
SELECT version();
Then inspect installed extensions:
SELECT
extname,
extversion
FROM pg_extension
ORDER BY extname;
This inventory often reveals dependencies that are easy to miss.
Choose the Target PostgreSQL Version
Do not approach the upgrade as simply:
PostgreSQL 14 → PostgreSQL 15
First determine which supported PostgreSQL release is the appropriate target for your organization.
Consider:
Application compatibility
Npgsql support
ORM compatibility
Extension availability
Hosting-provider support
Operational tooling
Internal upgrade policies
Expected support lifetime
Choosing a newer supported release can reduce the number of future major-version upgrades you need to perform, but the decision should be based on your application's compatibility and operational requirements.
Check the .NET Application Stack
The database server is only one part of the system.
A typical .NET application might look like this:
ASP.NET Core
|
v
Entity Framework Core
|
v
Npgsql
|
v
PostgreSQL 14
After the upgrade:
ASP.NET Core
|
v
Entity Framework Core
|
v
Npgsql
|
v
Target PostgreSQL Version
Before migrating, verify that the versions of .NET, EF Core, and Npgsql used by the application support your target PostgreSQL release.
For example, inspect the project file:
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore"
Version="..." />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL"
Version="..." />
</ItemGroup>
Do not upgrade every dependency at the same time without a reason. Separating database-version changes from unrelated application changes makes failures much easier to diagnose.
Capture Your Important Queries
Application compatibility testing should focus on real workload patterns.
For an EF Core application, identify important LINQ queries:
var orders = await dbContext.Orders
.Where(o => o.CustomerId == customerId)
.OrderByDescending(o => o.CreatedAt)
.Take(50)
.ToListAsync();
Also capture the generated SQL where practical.
Test queries involving:
Joins
Aggregations
Pagination
Sorting
JSON
Arrays
Full-text search
Transactions
Bulk operations
Database functions
A query that works syntactically on both versions can still have a different execution plan.
Test Against Production-Like Data
One of the most common upgrade-testing mistakes is using a small development database.
Suppose production has:
orders: 150 million rows
customers: 8 million rows
while the test environment contains:
orders: 50,000 rows
customers: 5,000 rows
A query that looks fast in development may behave differently at production scale.
You do not necessarily need a complete production copy. You need a dataset that reproduces important characteristics such as:
Sensitive production data should also be handled according to your organization's security and privacy requirements.
Compare Query Execution Plans
Before the migration, collect execution plans for important queries.
For example:
EXPLAIN (ANALYZE, BUFFERS)
SELECT
o.id,
o.total_amount,
o.created_at
FROM orders o
WHERE o.customer_id = 1001
ORDER BY o.created_at DESC
LIMIT 50;
Run equivalent tests against the current PostgreSQL environment and the target version.
Look for:
Sequential scans where an index was previously used
Different join algorithms
Increased row estimates
Higher execution time
Increased buffer reads
Additional sorting
Changes in aggregation strategy
Do not assume that a different plan automatically means a regression. Query planners can legitimately select different strategies.
The important thing is to measure the resulting behavior.
Test Database Extensions
Extensions deserve special attention during major-version upgrades.
List the extensions currently installed:
SELECT
extname,
extversion
FROM pg_extension;
For every extension, determine:
Is it supported on the target PostgreSQL version?
Is a compatible version available?
Does the upgrade process require additional steps?
Does the application depend directly on the extension?
This is particularly important for applications using specialized indexing, search, geospatial functionality, or other PostgreSQL extensions.
Do not assume that because PostgreSQL itself supports the target version, every extension in your environment automatically does.
Test Migrations and Database Objects
Applications often contain more database logic than developers realize.
Review:
Tables
Indexes
Views
Materialized views
Functions
Triggers
Sequences
Generated columns
Constraints
Custom types
Extensions
For EF Core applications, verify that migrations still work against the target database.
For example:
dotnet ef database update
Run migrations against a disposable target-version database before attempting production deployment.
This gives you an opportunity to identify database-object compatibility problems without risking production data.
Validate Backup and Restore
A migration plan is incomplete without a recovery plan.
Before upgrading, verify that your backups can actually be restored.
A backup that successfully completes but cannot be restored is not a reliable recovery strategy.
Your test should cover:
Production Backup
|
v
Backup Storage
|
v
Restore
|
v
Target PostgreSQL Environment
|
v
Application Validation
Measure the restore process and record the time required.
This gives the team a realistic understanding of recovery capability.
Choose an Upgrade Strategy
There are several approaches to a major PostgreSQL upgrade.
| Approach | Advantages | Considerations |
|---|
| In-place upgrade | Can be straightforward | Requires careful downtime planning |
| Logical migration | Can provide more migration flexibility | More operational complexity |
| Dump and restore | Familiar and portable | Can be slow for large databases |
| Managed-service upgrade | Provider may automate parts | Provider-specific limitations |
| Blue/green approach | Strong rollback potential | Requires additional infrastructure |
The right choice depends on database size, downtime requirements, infrastructure, replication architecture, and operational capabilities.
There is no single migration method that is best for every PostgreSQL installation.
Build an Upgrade Test Environment
A strong upgrade process should have at least one environment that resembles production.
A useful structure is:
PostgreSQL 14
|
| Baseline
v
Production-Like Test Data
|
v
Target PostgreSQL
|
| Compatibility Testing
v
.NET Application
Run the same application test suite against both versions.
Include:
Authentication
CRUD operations
Search
Reporting
Background jobs
Transactions
Scheduled tasks
APIs
Batch processing
The database upgrade should be tested as an application change, not just an infrastructure change.
Run Application-Level Regression Tests
Automated integration tests are especially valuable.
For example:
[Fact]
public async Task Should_Create_Order()
{
await using var context = CreateDbContext();
var order = new Order
{
CustomerId = 1001,
Status = "Pending",
TotalAmount = 149.99m
};
context.Orders.Add(order);
await context.SaveChangesAsync();
var savedOrder = await context.Orders
.FirstAsync(x => x.Id == order.Id);
Assert.Equal(149.99m, savedOrder.TotalAmount);
}
The same test suite should run against the existing PostgreSQL version and the target version.
This catches problems that database-only testing cannot detect.
Test Connection Pooling and Transactions
Production applications normally use connection pooling.
A basic .NET connection string might look like:
Host=localhost;
Port=5432;
Database=appdb;
Username=appuser;
Password=secret;
Pooling=true;
Maximum Pool Size=100;
The actual values should match your application's requirements.
Test:
Also check that failed database operations do not leave application connections or transactions in an unexpected state.
Common Upgrade Mistakes
Waiting Until the Support Deadline
The November deadline should be treated as a reason to start planning early, not as the migration date.
Testing Only Schema Compatibility
A database can accept the schema while application queries still experience regressions.
Ignoring Extensions
Extensions can introduce independent compatibility requirements.
Changing Too Many Variables
Avoid combining the PostgreSQL upgrade with large application refactoring, ORM migration, infrastructure redesign, and unrelated dependency upgrades.
Keeping the change set controlled makes troubleshooting significantly easier.
Skipping Restore Testing
A migration without a tested recovery path creates unnecessary operational risk.
Troubleshooting Upgrade Problems
A Query Became Slower
Start with:
EXPLAIN (ANALYZE, BUFFERS)
SELECT ...;
Compare execution plans and check statistics, indexes, data distribution, and configuration.
EF Core Queries Fail
Capture the generated SQL and run it directly against the target PostgreSQL version.
This helps determine whether the issue originates from PostgreSQL, EF Core, or the database driver.
An Extension Cannot Be Installed
Check whether a compatible extension version exists for the target PostgreSQL release and whether your hosting environment supports it.
The Application Cannot Connect
Check:
Best Practices
Start with an inventory. Know exactly what PostgreSQL 14 supports in your environment.
Choose the target deliberately. Consider support lifetime and application compatibility.
Test the complete .NET stack. PostgreSQL, Npgsql, EF Core, and the application should be tested together.
Use production-like data. Query behavior depends heavily on data volume and distribution.
Compare execution plans. Investigate meaningful changes rather than assuming they are regressions.
Test extensions separately. Extension compatibility can become a migration blocker.
Validate backups and restores. Recovery should be demonstrated, not assumed.
Rehearse the migration. A dry run exposes operational problems before production.
Keep the change set controlled. Avoid unrelated application changes during the database upgrade.
Define rollback criteria. Decide in advance what conditions require stopping or reversing the migration.
Frequently Asked Questions
When should a PostgreSQL 14 upgrade be completed?
PostgreSQL 14 is scheduled to reach end of support on November 12, 2026. Teams should plan the migration early enough to complete compatibility testing and address unexpected issues before that date.
Do I need to upgrade Npgsql?
You should verify that your Npgsql version supports the target PostgreSQL release and your application stack. Do not upgrade it blindly; validate the dependency combination through testing.
Should I test with the complete production database?
Not necessarily. A production-like dataset can be sufficient if it reproduces the characteristics that influence your application's behavior. Follow your organization's data-security requirements when creating test datasets.
Is a PostgreSQL major upgrade always associated with application changes?
No. Many applications can continue working with minimal or no code changes, but that should be demonstrated through testing rather than assumed.
What is the most important upgrade test?
There is no single test. A reliable upgrade assessment combines functional testing, query-plan comparison, performance testing, extension validation, backup/restore testing, and application-level regression testing.
Conclusion
The PostgreSQL 14 support deadline should be treated as an engineering planning milestone, not a last-minute migration deadline. A successful upgrade depends on understanding the entire dependency chain from the PostgreSQL server through Npgsql and the .NET application.
Start by inventorying the current environment, selecting an appropriate target version, and building a production-like test environment. Then test real application queries, database objects, extensions, transactions, connection pooling, backups, and recovery procedures.
The most valuable upgrade preparation is a rehearsed process with measurable results. When the production migration finally happens, the team should already know how the application behaves on the target PostgreSQL version, how long the migration takes, what can go wrong, and what the recovery path looks like.