n8n environment variables for production: what to set and why
The n8n environment variables worth setting on a production instance: URLs, encryption key, Postgres, timeouts, logging, and the security defaults in 2.x.

On a production n8n instance, set at least these environment variables yourself: the public URLs (N8N_HOST, N8N_PROTOCOL, N8N_WEBHOOK_URL, and N8N_PROXY_HOPS behind a reverse proxy), a fixed N8N_ENCRYPTION_KEY that you back up, GENERIC_TIMEZONE, and the DB_* variables for Postgres. After that, the ones that save you later are an execution timeout, pruning limits that fit your disk, and JSON logs. n8n 2.x already ships safer security defaults, so most hardening is about not undoing them.
The short version:
| Variable | Default | Set it to |
|---|---|---|
N8N_HOST, N8N_PROTOCOL | localhost, http | Your domain and https |
N8N_WEBHOOK_URL | empty | https://<your-domain>/ behind a reverse proxy |
N8N_PROXY_HOPS | 0 | The number of proxies in front of n8n, usually 1 |
N8N_ENCRYPTION_KEY | generated on first start | A long random string you store safely |
GENERIC_TIMEZONE | America/New_York | Your timezone, for example Europe/Berlin |
DB_TYPE | sqlite | postgresdb, plus the DB_POSTGRESDB_* variables |
EXECUTIONS_TIMEOUT | -1 (no timeout) | A ceiling in seconds, for example 3600 |
N8N_LOG_FORMAT | text | json if a log system reads the logs |
Defaults come from n8n's environment variable reference and the config source at 2.46.7, the stable release when we checked on November 10, 2026. Where the two disagree, this guide says so and follows the source.
What we checked on n8n 2.46.7
We started n8n 2.46.7 locally with a test set of these variables and read its startup log:
WEBHOOK_URL(the old name) still worked, and n8n logged a deprecation notice at startup: "WEBHOOK_URL -> Use N8N_WEBHOOK_URL instead".N8N_ENCRYPTION_KEY_FILEpointing at a file with a trailing newline: n8n printed "The file specified by N8N_ENCRYPTION_KEY_FILE contained leading or trailing whitespace; the value was trimmed", and wrote the trimmed key to.n8n/config, which it created with0600permissions.N8N_LOG_FORMAT=jsonturned every log line into a JSON object withlevel,messageandmetadata.N8N_METRICS=truemade/metricsreturn Prometheus metrics (lines starting withn8n_), and/healthzanswered{"status":"ok"}.N8N_BLOCK_ENV_ACCESS_IN_NODEleft unset: a workflow with the expression{{ $env.HOME }}failed with "access to env vars denied". With the variable set tofalse, the same workflow succeeded.
Where to set them
With Docker Compose, put them under the n8n service's environment: key, or in an .env file that Compose reads. After a change, recreate the container (docker compose up -d) so the new values take effect. Our Docker Compose guide builds a complete stack with Postgres, Caddy and task runners.
For secrets, append _FILE to the variable name and point it at a file, such as a Docker or Kubernetes secret. n8n's configuration docs say most variables accept the suffix, with credentials and database settings the most useful. In the 2.46.7 source, n8n's config loader checks <NAME>_FILE for every variable it defines, and a source comment names N8N_ENCRYPTION_KEY_FILE explicitly. Two exceptions we know of:
- The task runner image doesn't read
_FILEvariables, per the task runner reference. Pass the runner token as a normal variable. - Variables that n8n reads straight from the process environment rather than through its config loader, such as
N8N_BLOCK_ENV_ACCESS_IN_NODE, don't get the_FILEtreatment.
URLs and the reverse proxy
These decide which URLs n8n shows in the editor and registers for webhooks. Get them wrong and webhook URLs point at localhost or plain http.
N8N_HOST(defaultlocalhost) andN8N_PROTOCOL(defaulthttp): the host name and protocol people use to reach n8n.N8N_WEBHOOK_URL: the public base URL for test and production webhooks behind a reverse proxy. The old nameWEBHOOK_URLis deprecated from n8n 2.35.0; the endpoints reference says it still works but logs a deprecation warning at startup.N8N_PROXY_HOPS(default0): the number of reverse proxies in front of n8n. n8n's reverse proxy guide sets it to1and has the last proxy passX-Forwarded-Forand the other forwarded headers.N8N_EDITOR_BASE_URL: the public editor URL, also used in emails n8n sends and as the SAML redirect URL. Set it when emails or SSO are in use.N8N_PATH(default/): the deployment reference warns that a sub-path behind a reverse proxy can cause folder navigation issues, and suggests a subdomain instead.
Our webhooks guide shows what goes wrong with test and production URLs when these are off.
The encryption key
n8n encrypts every credential in the database with N8N_ENCRYPTION_KEY. If you don't set it, n8n generates a random key on first launch and saves it in the .n8n folder. That works until the folder is lost: a new container without that volume, a restore to a new server, or a second instance. Without the original key, the stored credentials can't be decrypted.
Set it yourself, keep a copy outside the server, and use the same value everywhere the database is used. The docs say every queue mode worker needs it too (see our queue mode guide). The docs describe the variable for an instance whose settings file doesn't hold a key yet. On an instance that already runs, take the existing key from the .n8n/config file and set that value, rather than a new one.
# Generate a key once and store it somewhere safe
openssl rand -hex 32The database: Postgres instead of SQLite
DB_TYPE defaults to sqlite. For production, n8n's database reference covers Postgres with these variables (defaults in brackets):
DB_TYPE=postgresdbDB_POSTGRESDB_HOST(localhost),DB_POSTGRESDB_PORT(5432),DB_POSTGRESDB_DATABASE(n8n),DB_POSTGRESDB_USER(postgres),DB_POSTGRESDB_SCHEMA(public)DB_POSTGRESDB_PASSWORD, or betterDB_POSTGRESDB_PASSWORD_FILEDB_POSTGRESDB_POOL_SIZE(2): parallel connections. The docs say raising it may help, but too many connections can hurt performance.
If you stay on SQLite for a small instance, its data lives in the same .n8n folder as the encryption key, so that volume is the whole instance.
Executions: timeouts, pruning and concurrency
From the executions reference, matched against the 2.46.7 source:
| Variable | Default | What it does |
|---|---|---|
EXECUTIONS_TIMEOUT | -1 | Default timeout in seconds for every workflow; -1 means none, so a run that hangs keeps going until someone stops it. |
EXECUTIONS_TIMEOUT_MAX | 3600 | The highest timeout a user can set on a single workflow. |
EXECUTIONS_DATA_PRUNE | true | Deletes old execution data on a rolling basis. |
EXECUTIONS_DATA_MAX_AGE | 336 | Hours to keep executions (14 days). |
EXECUTIONS_DATA_PRUNE_MAX_COUNT | 10000 | Maximum executions kept; 0 means no limit. |
EXECUTIONS_DATA_SAVE_ON_SUCCESS, EXECUTIONS_DATA_SAVE_ON_ERROR | all, all | Set success to none to store only failed runs. |
N8N_CONCURRENCY_PRODUCTION_LIMIT | -1 | Maximum production executions running at once; -1 disables the limit in regular mode. |
A timeout is the one most instances are missing. Pick a ceiling that's longer than your slowest legitimate workflow; individual workflows can still set their own timeout up to EXECUTIONS_TIMEOUT_MAX. For pruning in depth, including how to free disk space on SQLite, see prune n8n execution data.
Security: defaults that are already on in 2.x
n8n 2.0 changed several security defaults, according to its 2.0 breaking changes. The 2.46.7 source matches the breaking-changes page. The security reference page still lists the older defaults for some of them (checked November 10, 2026), so don't copy values from that table without checking.
| Variable | Default in 2.x | What it means |
|---|---|---|
N8N_BLOCK_ENV_ACCESS_IN_NODE | true | Expressions and the Code node can't read environment variables. In the source, access is blocked unless the variable is exactly false. |
N8N_RESTRICT_FILE_ACCESS_TO | ~/.n8n-files | The Read/Write Files from Disk and Read Binary Files nodes only reach this folder. |
N8N_BLOCK_FILE_ACCESS_TO_N8N_FILES | true | Blocks file nodes from the .n8n folder, where the encryption key lives. |
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS | true | n8n requires 0600 permissions on its settings file. The docs say to set it to false only where file permissions aren't supported, such as Windows. |
N8N_GIT_NODE_DISABLE_BARE_REPOS | true | The Git node refuses bare repositories. |
N8N_SECURE_COOKIE | true | The login cookie is only sent over HTTPS. |
If a workflow fails with access to env vars denied, that's N8N_BLOCK_ENV_ACCESS_IN_NODE doing its job. The 2.0 breaking changes suggest credentials or other secure methods for sensitive values rather than turning env access back on.
The safe move is to leave these alone. Don't set N8N_SECURE_COOKIE=false to make plain-HTTP access work on a public server; put n8n behind HTTPS instead.
Two settings that are off by default and worth considering:
N8N_SSRF_PROTECTION_ENABLED(defaultfalse): guards outbound requests whose destination comes from user input against internal targets such aslocalhost, private network ranges and the cloud metadata address169.254.169.254, with allow and block lists for hosts and IP ranges, per the SSRF protection reference. Worth turning on when workflows build URLs from data that outsiders control.N8N_PUBLIC_API_DISABLED(defaultfalse): turns off n8n's public REST API if you don't use it.
Logging and monitoring
From the logs reference and the endpoints reference:
N8N_LOG_LEVEL(info):error,warn,infoordebug. Usedebugonly while troubleshooting.N8N_LOG_FORMAT(text):jsonprints one JSON object per line with the message, level, timestamp and metadata, which log collectors parse without extra rules.N8N_LOG_OUTPUT(console):console,fileor both, comma-separated.N8N_METRICS(false): turns on the Prometheus/metricsendpoint.N8N_ENDPOINT_HEALTH(healthz): the path of the health check endpoint that uptime monitors and container health checks call.
Optional: telemetry, notifications and shutdown
N8N_DIAGNOSTICS_ENABLED(true): shares anonymous telemetry with n8n. The deployment reference notes that with it set tofalse, you can't enable Ask AI in the Code node.N8N_VERSION_NOTIFICATIONS_ENABLED(true): shows notifications about new versions and security updates. Leave it on unless another process tells you about releases.N8N_GRACEFUL_SHUTDOWN_TIMEOUT(30): seconds n8n waits for components to shut down before the process exits.
A production environment block
Putting it together for the n8n service in Docker Compose. Replace the placeholders, and keep the secrets in files:
services:
n8n:
environment:
N8N_HOST: n8n.example.com
N8N_PROTOCOL: https
N8N_WEBHOOK_URL: https://n8n.example.com/
N8N_PROXY_HOPS: 1
N8N_ENCRYPTION_KEY_FILE: /run/secrets/n8n_encryption_key
GENERIC_TIMEZONE: Europe/Berlin
TZ: Europe/Berlin
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD_FILE: /run/secrets/postgres_password
EXECUTIONS_TIMEOUT: 3600
N8N_LOG_FORMAT: json
secrets:
- n8n_encryption_key
- postgres_password
secrets:
n8n_encryption_key:
file: ./secrets/n8n_encryption_key.txt
postgres_password:
file: ./secrets/postgres_password.txtCompose mounts each secret at /run/secrets/<name> inside the container. Add the task runner variables from our task runners guide and, for files and binary data, the storage settings from the binary data guide.
Next steps
- Build the whole stack: self-host n8n with Docker Compose, Postgres and HTTPS.
- Before changing variables on a running instance, take a backup: update self-hosted n8n safely.
- Scale out with workers, which need the same encryption key: n8n queue mode.
Sources
- Environment variables overview (n8n docs)
- Deployment environment variables (n8n docs)
- Endpoints environment variables (n8n docs)
- Database environment variables (n8n docs)
- Executions environment variables (n8n docs)
- Security environment variables (n8n docs)
- Logs environment variables (n8n docs)
- Configuration methods, the _FILE suffix (n8n docs)
- Set a custom encryption key (n8n docs)
- n8n 2.0 breaking changes, security defaults (n8n docs)
- n8n config package at 2.46.7 (n8n on GitHub)
Editorial team
The then8nblog editorial team researches every article from n8n's release notes, documentation and source code, states the n8n version each guide was tested on, and has every post reviewed by a human editor before it goes live.



