NodeRecipe.

n8n Docker Setup: Run n8n in a Container Without Losing Your Data (2026)

A complete n8n Docker setup guide: the run command explained flag by flag, volumes that actually persist, Compose, updates, and fixes for the usual errors.

By Ali Ilyas · · Updated July 27, 2026

The fastest n8n Docker setup is a single command, and you'll have the editor open at http://localhost:5678 in about two minutes. The part that trips people up comes later — the container restarts, and every workflow is gone. This guide covers the command, then the things that decide whether your instance survives its first update: where n8n actually stores data, which environment variables matter, and how to pin and roll back versions.

No prior Docker experience is assumed. Where a flag matters, I explain what it does rather than asking you to paste it on faith.

What's on this page

Do you want Docker setup, or full self-hosting?

These are two different jobs, and mixing them up wastes an afternoon.

This guide is about the container itself: how the n8n image runs, where it keeps state, how to update it safely, and what to do when Docker misbehaves. It applies whether you're on a laptop or a server.

Putting n8n on the public internet — a domain, HTTPS certificates, a reverse proxy, Postgres, backups, firewall rules — is a separate concern. That's covered step by step in the complete guide to self-hosting n8n.

If you just want n8n running locally to build and test workflows, stay here. If you want a URL your team can reach, read this first, then that.

What you'll need

  • Docker installed. On Linux, Docker Engine plus the Compose plugin. On Windows or macOS, Docker Desktop.
  • About 1 GB of free RAM. n8n is comfortable in 2 GB once you have a few active workflows.
  • A terminal. Every command below is copy-pasteable.

Verify Docker is working before going further:

docker --version
docker compose version

If the second command errors, you have an older standalone docker-compose binary. The commands still work — write them as docker-compose instead of docker compose.

Start n8n in one command

Create a volume for n8n's data, then start the container:

docker volume create n8n_data

docker run -it --rm \
  --name n8n \
  -p 5678:5678 \
  -e GENERIC_TIMEZONE="Europe/Berlin" \
  -e TZ="Europe/Berlin" \
  -e N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true \
  -v n8n_data:/home/node/.n8n \
  docker.n8n.io/n8nio/n8n

Open http://localhost:5678 and create your owner account.

What each part does:

  • -p 5678:5678 maps the container's port to your machine. Change the left number if 5678 is taken: -p 8080:5678 serves n8n on http://localhost:8080.
  • GENERIC_TIMEZONE sets the timezone for schedule-based nodes. Get this wrong and your Schedule Trigger fires at the wrong hour. TZ sets the timezone for the operating system inside the container, which affects log timestamps. Set both, to the same value.
  • N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true locks down the config file that holds your encryption key.
  • -v n8n_data:/home/node/.n8n is the important one. See the next section.

Two flags deserve a warning. -it attaches the container to your terminal, so closing that terminal stops n8n. --rm deletes the container when it stops. That combination is right for trying n8n out and wrong for anything you care about. For a container that keeps running, drop both and add -d:

docker run -d --name n8n --restart unless-stopped \
  -p 5678:5678 \
  -e GENERIC_TIMEZONE="Europe/Berlin" \
  -e TZ="Europe/Berlin" \
  -v n8n_data:/home/node/.n8n \
  docker.n8n.io/n8nio/n8n

--restart unless-stopped brings n8n back after a reboot or a crash.

On n8n 1.x, add -e N8N_RUNNERS_ENABLED=true. Task runners are how n8n executes code nodes, and on the 1.x line you have to opt in. From version 2.0 the variable is deprecated and you no longer need to set it. If you're on 2.0 or later and copied an older tutorial, you can drop it.

Where n8n stores your data

n8n keeps everything in /home/node/.n8n inside the container. That directory holds:

  • the SQLite database with your workflows, credentials, and execution history
  • the encryption key that your saved credentials are encrypted against
  • instance settings

Containers are disposable. Anything written inside one that isn't mapped to a volume disappears when the container is removed — and docker run --rm, docker rm, and most update procedures all remove containers. This is the single most common way people lose an n8n instance.

The -v n8n_data:/home/node/.n8n flag maps a Docker-managed named volume to that directory, so the data lives outside the container's lifecycle. Confirm it exists:

docker volume inspect n8n_data

The encryption key detail is worth dwelling on. Your credentials are encrypted with a key stored in that directory. Lose the volume and you don't just lose workflows — every saved credential becomes undecryptable, even if you have a database backup. Restoring means re-entering every API key by hand.

You can use a bind mount instead, pointing at a folder you can see:

-v ~/n8n-data:/home/node/.n8n

That makes backups as easy as copying a folder, but it introduces a permissions problem on Linux — see common errors below. Named volumes are the lower-friction default; bind mounts are better when you want direct file access.

docker run vs. Docker Compose

A long docker run command is fine once. It stops being fine the moment you need to remember it.

docker runDocker Compose
Trying n8n for ten minutesGoodOverkill
Keeping an instance aroundPainful — you must retype every flagGood
Adding Postgres or RedisManual networkingHandles it
UpdatingStop, remove, retype the commandpull then up -d
Config lives inYour shell historyA file you can version-control

Anything you intend to keep belongs in Compose. The configuration becomes a file you can read, diff, and back up, instead of a command you half-remember.

A Compose file for everyday local use

Create a folder, add a docker-compose.yml, and start it. This setup uses SQLite, which is the right choice for local development and light use:

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - GENERIC_TIMEZONE=Europe/Berlin
      - TZ=Europe/Berlin
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:

Start it, and watch the logs:

docker compose up -d
docker compose logs -f

Press Ctrl+C to stop following the logs — the container keeps running. To stop n8n itself:

docker compose down

down removes the container but not the named volume, so your workflows survive. Adding -v to that command deletes the volume too, which is the destructive version. Don't type docker compose down -v on an instance you care about.

For a production setup with Postgres, HTTPS, and a reverse proxy, use the Compose file in the self-hosting guide instead — SQLite is fine locally but not what you want under real load.

The environment variables that matter

There are well over a hundred. These are the ones that change outcomes:

VariableWhy you'd set it
GENERIC_TIMEZONETimezone for Schedule Trigger and other time-based nodes. Wrong value = jobs at the wrong hour.
TZOperating-system timezone in the container. Affects log timestamps. Match it to GENERIC_TIMEZONE.
N8N_ENCRYPTION_KEYSets the credential encryption key explicitly instead of letting n8n generate one. Useful when you need reproducible deployments.
N8N_SECURE_COOKIEDefaults to true, which means the session cookie is only sent over HTTPS. Accessing n8n over plain http:// on anything other than localhost will fail to log in until you set this to false.
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONSRestricts permissions on the settings file holding your encryption key.
N8N_PORTChanges the port inside the container. Usually unnecessary — remap with -p instead.
N8N_RUNNERS_ENABLEDRequired as true on 1.x to enable task runners. Deprecated from 2.0 onward.

To use Postgres instead of SQLite, add:

DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD=your-password

Even on Postgres, keep the /home/node/.n8n volume mounted. The database moves to Postgres, but the encryption key and instance settings still live in that directory.

Updating n8n, and rolling back

The image tag you use decides how much control you have. docker.n8n.io/n8nio/n8n with no tag means latest, so every pull can move you forward by an unknown amount. For anything you depend on, pin a specific version:

image: docker.n8n.io/n8nio/n8n:1.80.0

Back up before updating. With a named volume, the quickest snapshot is a tarball:

docker run --rm -v n8n_data:/data -v "$PWD":/backup alpine \
  tar czf /backup/n8n-backup.tar.gz -C /data .

Then update:

docker compose pull
docker compose down
docker compose up -d

Rolling back is why pinning matters: change the tag in docker-compose.yml back to the previous version and run docker compose up -d again. On latest, you have no easy way to name the version that was working.

Check what you're actually running:

docker compose logs n8n | head -20

Docker Desktop on Windows and macOS

The commands are identical, with three differences worth knowing.

Localhost works as expected. http://localhost:5678 reaches the container.

Bind mounts are slower. File operations across the Windows or macOS boundary carry overhead. Named volumes are meaningfully faster on these platforms — another reason to prefer them.

On Windows, keep files inside WSL2. If you use bind mounts, put the project folder in the WSL2 filesystem (\\wsl$\...) rather than under C:\Users\.... Crossing the filesystem boundary is slow and causes intermittent permission oddities.

Common Docker errors and fixes

All my workflows disappeared after a restart. The container ran without a volume mapped to /home/node/.n8n. Unless you had a backup, that data is gone — containers don't keep filesystem changes after removal. Add -v n8n_data:/home/node/.n8n and rebuild. Verify with docker volume inspect n8n_data before you invest hours in building workflows.

EACCES: permission denied writing to /home/node/.n8n. This hits bind mounts on Linux. The n8n container runs as the node user (UID 1000), and your host folder is owned by someone else. Fix ownership on the host:

sudo chown -R 1000:1000 ~/n8n-data

Named volumes don't have this problem, which is the main argument for them.

port is already allocated on 5678. Something else holds the port — often a previous n8n container. Find it:

docker ps -a | grep 5678

Remove the old container, or remap: -p 8080:5678.

I can't log in — the page reloads back to the sign-in screen. You're reaching n8n over plain http:// on a LAN IP or hostname. N8N_SECURE_COOKIE defaults to true, so the session cookie is only sent over HTTPS and never comes back. For local network use, set N8N_SECURE_COOKIE=false. Don't do that on a public server — set up HTTPS properly instead.

The container exits immediately. Read the logs, which almost always name the cause:

docker logs n8n

Malformed environment variables and unreachable database hosts are the usual culprits.

Webhooks show a localhost URL that external services can't reach. Expected: n8n advertises the address it thinks it has. For webhooks reachable from the internet you need a public URL and the WEBHOOK_URL variable, which is part of putting n8n on a real domain.

Frequently asked questions

Is the Docker version of n8n free? Yes. The image is the Community Edition, which is free to self-host with unlimited workflow executions. Some enterprise features are licensed separately.

Do I need Docker Compose, or is docker run enough? docker run is enough to try it. Use Compose for anything you keep — it turns a command you have to remember into a file you can back up.

Can I run n8n in Docker on a Raspberry Pi? Yes, on 64-bit ARM hardware with enough RAM. A Pi 4 with 2 GB handles light workloads.

How do I move an instance to another machine? Copy the /home/node/.n8n volume contents, including the encryption key. Move the database without the key and your credentials will be unreadable.

Where does n8n store workflows in Docker? In the SQLite database inside /home/node/.n8n, unless you configured Postgres — in which case workflows live in Postgres, while the encryption key and settings remain in that directory.


Official references worth bookmarking: n8n's Docker installation docs and Docker's own guide to volumes.

Ready to build? Grab the ready-made docker-compose.yml files from this guide, plus starter workflow templates, on our templates page. Taking this to a real server with a domain and HTTPS? That's the complete self-hosting walkthrough.