n8n ships new releases frequently, with security fixes, new nodes and bug fixes. When you self-host it with Docker Compose, updating means pulling a newer image and recreating the container, but a careless update can break workflows or run database migrations you cannot undo. In this tutorial you will back up your n8n instance, update it to the latest version, verify that it works, and learn how to roll back if something goes wrong.
Prerequisites
To follow this guide you need:
- A server running n8n with Docker Compose, for example on a CubePath VPS with Ubuntu 24.04. This guide assumes the project lives in
/opt/n8nand uses PostgreSQL; adjust the path and service names to your setup. - A non-root user with
sudoprivileges, or a user in thedockergroup. - Docker Engine with the Compose plugin (
docker compose, not the legacydocker-composebinary). - Enough free disk space for a database dump and a second copy of the n8n image (about 2 GB).
Step 1 - Checking the current version and reading the release notes
Go to the directory that contains your docker-compose.yml (or compose.yaml):
cd /opt/n8n
List the services so you know their names. The rest of this guide assumes they are called n8n and postgres:
docker compose ps
NAME IMAGE SERVICE STATUS PORTS
n8n-n8n-1 docker.n8n.io/n8nio/n8n n8n Up 3 weeks 0.0.0.0:5678->5678/tcp
n8n-postgres-1 postgres:16 postgres Up 3 weeks 5432/tcp
Check which n8n version you are running:
docker compose exec n8n n8n --version
2.1.4
Before updating, read the release notes on the n8n GitHub releases page and the "Breaking changes" section of the n8n documentation for every version between yours and the latest one. Minor releases are usually safe; a major version jump can remove deprecated features or change behavior, and n8n publishes a migration guide for it.
Also check which tag your Compose file uses:
grep -n "image:" docker-compose.yml
3: image: docker.n8n.io/n8nio/n8n
12: image: postgres:16
An image without a tag (or with :latest) follows the latest stable release. If the file pins a version such as docker.n8n.io/n8nio/n8n:2.1.4, edit it with nano docker-compose.yml and set the version you want to move to.
Step 2 - Backing up the database and the data volume
n8n stores workflows, credentials and execution history in the database, and keeps its encryption key in /home/node/.n8n inside the container. You need both to restore an instance, because credentials cannot be decrypted without that key.
Create a backup directory:
sudo mkdir -p /opt/n8n-backups
Dump the PostgreSQL database. Replace n8n with the POSTGRES_USER and POSTGRES_DB values from your .env or Compose file:
docker compose exec -T postgres pg_dump -U n8n -d n8n -Fc | sudo tee /opt/n8n-backups/n8n-$(date +%F).dump > /dev/null
Find the name of the volume mounted at /home/node/.n8n. Compose prefixes volume names with the project name:
docker volume ls
DRIVER VOLUME NAME
local n8n_n8n_data
local n8n_db_storage
Archive the n8n data volume with a temporary container:
docker run --rm -v n8n_n8n_data:/data:ro -v /opt/n8n-backups:/backup alpine tar czf /backup/n8n_data-$(date +%F).tar.gz -C /data .
Check that both files exist and are not empty:
ls -lh /opt/n8n-backups
-rw-r--r-- 1 root root 48M Sep 25 10:12 n8n-2026-09-25.dump
-rw-r--r-- 1 root root 1.2M Sep 25 10:13 n8n_data-2026-09-25.tar.gz
NoteIf your instance uses the default SQLite database instead of PostgreSQL, the database file (
database.sqlite) lives inside the data volume, so the volume archive is your full backup. Stop n8n withdocker compose stop n8nbefore archiving so the file is consistent.
Step 3 - Pulling the new image
Download the new image while the current version keeps running. This keeps downtime to the few seconds it takes to recreate the container:
docker compose pull n8n
[+] Pulling 1/1
n8n Pulled
Step 4 - Recreating the container
Apply the update. Compose only recreates the containers whose image or configuration changed, so PostgreSQL keeps running:
docker compose up -d
[+] Running 2/2
Container n8n-postgres-1 Running
Container n8n-n8n-1 Started
There is no need to run docker compose down first. down removes the containers and the network, which adds downtime and gives you nothing extra here.
Step 5 - Verifying the update
Follow the n8n logs while it starts. On a version jump, n8n runs its database migrations at this point:
docker compose logs -f n8n
Wait until you see a line like this, then press CTRL+C:
Editor is now accessible via:
http://localhost:5678
Confirm the new version:
docker compose exec n8n n8n --version
2.4.0
Check the health endpoint from the server:
curl -s http://localhost:5678/healthz
{"status":"ok"}
Finally, log in to the editor, open a couple of important workflows and run them manually, and check that credentials still connect.
Step 6 - Cleaning up old images
Each update leaves the previous image on disk. Once you are happy with the new version, remove unused images:
docker image prune
Keep the backups from Step 2 for at least a few days before deleting them.
Rolling back to the previous version
If the new version breaks something, pin the old version in docker-compose.yml, for example:
image: docker.n8n.io/n8nio/n8n:2.1.4
Database migrations are not always reversible, so restore the database dump before starting the old version. Stop n8n, restore the dump, and start again:
docker compose stop n8n
docker compose exec -T postgres pg_restore -U n8n -d n8n --clean --if-exists < /opt/n8n-backups/n8n-2026-09-25.dump
docker compose up -d
Verify the version with docker compose exec n8n n8n --version as in Step 5.
Updating an npm installation
If you installed n8n with npm instead of Docker, back up ~/.n8n and your database, then install the latest release globally and restart the service that runs it:
sudo npm install -g n8n@latest
n8n --version
Troubleshooting
docker-compose: command not found. The legacy v1 binary is no longer maintained. Usedocker compose(with a space), provided by thedocker-compose-pluginpackage from Docker's repository.- Credentials fail with "could not be decrypted". The container started with a different encryption key. Make sure the data volume is mounted at
/home/node/.n8n, or thatN8N_ENCRYPTION_KEYin your environment has the same value as before. - The container restarts in a loop after the update. Read
docker compose logs n8n. Migration errors usually point to a skipped major version or an unsupported database version: roll back and follow the migration guide for that release.
Conclusion
You backed up your n8n database and encryption key, updated n8n to the latest image with only a few seconds of downtime, and verified the result with the version command and the health endpoint. To keep this routine safe, schedule regular database dumps with cron or a systemd timer, and consider pinning explicit version tags so updates only happen when you decide.
