PostgreSQL Step-by-Step Guide for Updating to Version 16 with Full Data Migration. Currently the recommended version.
Notes:
In this example, we are using “Immich Foto” as the container name; you must adapt the container name and the database container to your environment.
All commands in this guide are optimized for the Windows Command Prompt (CMD).
Before updating, verify that PostgreSQL version 16 is compatible with your application.
🎯 What to expect
This upgrade moves your PostgreSQL database from version 14 to the recommended version 16. In addition to the version upgrade, the vector extension is also being updated from pgvecto.rs to VectorChord – the current PostgreSQL standard method with significant performance improvements for vector operations.
The process uses logical backup and restore (pg_dumpall / psql), which is the safest method for major upgrades.
Special features of this guide:
- Explanation of the critical
shm_sizesetting for PostgreSQL 16 - Why
POSTGRES_INITDB_ARGS: '--data-checksums'protects your data - Troubleshooting for common issues
📋 Prerequisites
- Running PostgreSQL installation with Docker Compose
- Sufficient free disk space (at least size of current database + 20%)
- Access to the Docker host console
Video: PostgreSQL Update to Version.16, Major Upgrade Including Data Migration
Language: 🇩🇪|🇬🇧
☝️ Use YouTube subtitles for all languages.
🔧 Step 1: Prepare the Docker Compose file
Open your docker-compose.yml and replace the existing PostgreSQL service:
OLD Service (PostgreSQL 14 with pgvecto.rs):
yaml
db:
image: postgres:14
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
restart: always
NEW Service (PostgreSQL 16 with VectorChord):
yaml
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
restart: always
shm_size: 128mb
Save the file.
🛑 Step 2: Stop dependent services
Stop all services that access the database:
cmd
docker compose stop immich-server immich-machine-learning redis
Adjust the service names to match your environment.
💾 Step 3: Create a database backup
Create a complete backup:
cmd
docker exec immich_postgres pg_dumpall -c -U postgres > immich_backup.sql
Check if the backup was successful:
cmd
dir immich_backup.sql
The file should have a reasonable size (not 0 bytes).
🗑️ Step 4: Remove the old database container
cmd
docker compose down db
The old container is deleted, but your data in the volume remains.
🚨 Step 5: Clear the database volume (critical!)
The new PostgreSQL 16 container cannot start with old PostgreSQL 14 data. You must clear the volume:
First, check where your data is located:
cmd
type .env | findstr DB_DATA_LOCATION
Depending on the path type:
Case 1 – Relative path (starts with . or ./):
cmd
rmdir /s /q postgres
Case 2 – Absolute path (e.g., D:\DockerData\postgres):
cmd
rmdir /s /q D:\DockerData\postgres
Case 3 – Docker volume:
cmd
docker volume ls docker volume rm INSERT_VOLUME_NAME_HERE
⚠️ Warning: This step deletes the old PostgreSQL 14 data. Make sure your backup from Step 3 exists!
🚀 Step 6: Start the new PostgreSQL 16 container
cmd
docker compose up -d db
The container now initializes an empty database cluster with PostgreSQL 16 and VectorChord, including:
- Data Checksums (via
--data-checksums) - Increased Shared Memory (via
shm_size: 128mb)
Check if the container is running:
cmd
docker ps | findstr postgres
The output should show the container with status Up.
If there are problems, check the container logs:
cmd
docker logs immich_postgres --tail 50
📥 Step 7: Import the backup into the new database
cmd
docker exec -i immich_postgres psql -U postgres < immich_backup.sql
This process may take several minutes depending on the database size. Do not interrupt!
Note: For very large databases, the import may take an hour or longer – this is normal.
🔄 Step 8: Restart all services
cmd
docker compose up -d
✅ Step 9: Verify success
Check the PostgreSQL version:
cmd
docker exec immich_postgres psql -U postgres -c "SHOW server_version;"
Expected output: 16.x (not 14.x)
Check if checksums are enabled:
cmd
docker exec immich_postgres psql -U postgres -c "SELECT datname, datchecksum FROM pg_database;"
Check the logs for errors:
cmd
docker compose logs --tail 50
❓ The two important special questions – explained
1. Why shm_size: 128mb?
Shared Memory (/dev/shm) is a temporary memory area that PostgreSQL uses for parallel queries and vector operations.
The problem: Docker only allocates 64 MB by default – too little for PostgreSQL 16.
The consequences without this setting:
text
ERROR: could not resize shared memory segment FATAL: could not create shared memory segment
The solution: With shm_size: 128mb you get sufficient shared memory. For very large databases (>50,000 entries), 256 MB or 512 MB are recommended.
2. What does POSTGRES_INITDB_ARGS: '--data-checksums' do?
This enables checksums for every data page in PostgreSQL.
Advantages:
- Detection of silent data corruption (defective hard drives, bitrot, RAM errors)
- Early warning system instead of unnoticed incorrect data
- Enables targeted recovery from backups
The cost: Only 2-3% performance overhead – perfectly acceptable for most applications.
Important: This only takes effect during the initial database initialization – exactly what happens during this upgrade.
🚨 Troubleshooting
Error: “Container is restarting”
Cause: The container cannot start, usually due to incompatible old data.
Solution:
- Stop container:
docker compose down db - Clear volume (see Step 5)
- Restart container:
docker compose up -d db - Re-import backup
Error: “psql: could not connect to server”
Cause: The PostgreSQL server is not running.
Solution:
cmd
docker ps -a | findstr postgres docker logs immich_postgres --tail 50
The logs will show the exact cause.
Error: “permission denied” during import
Cause: Permission issues inside the container.
Solution:
cmd
docker exec -i immich_postgres psql -U postgres -f - < immich_backup.sql
📊 After the upgrade
Recommended actions:
- Keep the backup – only delete
immich_backup.sqlafter successful operation - Monitor performance – indexes will be rebuilt during the first few hours
- Set up regular backups – now take advantage of the checksums
🎓 Conclusion
The major upgrade from PostgreSQL 14 to 16 is safe and clean with this procedure. The combination of:
- Logical backup (
pg_dumpall) - Cleaned database volume
- Migration from pgvecto.rs to VectorChord
- Additional optimizations (
shm_size,data-checksums)
makes your database future-proof and more robust against data corruption.
Important note: After this upgrade, you cannot simply return to the old container – the database structure is not backward compatible. A rollback would only be possible by restoring the old backup on a PostgreSQL 14 container.

Support / Donation Link for the Channel
If my posts have been helpful or supported you in any way, I’d truly appreciate your support 🙏
#PostgreSQL16 #PostgreSQLUpdate #MajorUpgrade #DatabaseMigration #DockerPostgreSQL #VectorChord #pgvectors