Upgrading & Pinning n8n
n8n ships inside the compose stack, so you upgrade it independently of the Circus API and frontend — a version bump touches only the n8n container. The one recommendation to internalise: pin a specific version rather than riding an implicit latest, so upgrades are deliberate.
Check what's running
cd /app/staging
VERSION=staging-latest docker compose -p staging --env-file .env -f deploy/docker-compose.prod.yml exec n8n n8n --version
Pin or upgrade
Edit deploy/docker-compose.prod.yml and give the n8n image an explicit tag:
image: n8nio/n8n → image: n8nio/n8n:1.52.0
Then pull and restart only n8n — the API, frontend, and Postgres are untouched:
VERSION=staging-latest docker compose -p staging --env-file .env -f deploy/docker-compose.prod.yml pull n8n
VERSION=staging-latest docker compose -p staging --env-file .env -f deploy/docker-compose.prod.yml up -d n8n
Verify with ... ps n8n and ... logs n8n --tail 20. (Swap -p staging / VERSION=staging-latest for the production equivalents when upgrading production.)
Why pin
An unpinned latest means an unrelated pull — or a rebuild — can silently move n8n to a new major version, and n8n's node behaviour and env-var handling do change across versions. Pinning makes every n8n upgrade an explicit, reviewable edit to the compose file, which is exactly what you want for the component that runs your workflows. Test an n8n upgrade on staging before applying it to production.