On this page
Look, I've been working with n8n deployments for over a year now, and when I saw the v2.0 announcement, my first thought wasn't "what cool features," it was "how many production workflows am I going to have to fix?"

And you know what? This release is genuinely good, but it's going to break your stuff if you don't prepare.
The December 2025 launch timeline
- Beta: December 8, 2025
- Stable: December 15, 2025
- Recommendation at announcement: test before migrating
Version 1.x will get 3 months of security patches after v2 releases, and then that's it.
The Good Stuff
Autosave is coming. Yes, finally. After how many years of people losing work? Better late than never.
Also: updated canvas interface, new sidebar, and "surprises."
But let's be real, you're not here for UI updates.
The Stuff That Will Actually Break Your Workflows
Security: They're Locking Everything Down
1. Code Node Can No Longer Access Environment Variables
N8N_BLOCK_ENV_ACCESS_IN_NODE=true # This is now the defaultReview Code nodes that rely on environment variables. Move sensitive values into n8n credentials and use nodes or integrations that support those credentials. Disabling the new restriction changes the security boundary; it should not be the default migration fix. 2.0 migration guidance.
2. Task runners are enabled by default
In n8n 2.0, Code-node executions use task runners by default. On a compatible 1.x release, N8N_RUNNERS_ENABLED=true lets you test this behavior before upgrading; the flag is no longer needed from 2.0.
JavaScript supports internal mode. Native Python requires external mode, and n8n recommends external runners with hardening for production or sensitive data. Enabling runners alone does not configure the external containers, their broker connection or their permissions. Runner setup.
3. Python Code Node: Complete Rewrite
They removed Pyodide (the browser-based Python). Now it's native Python only, task runners required, external mode mandatory.
What breaks:
_inputvariable (removed)- Dot notation access (removed)
- Any Python Code node without proper task runner setup (broken)
This is better long-term, but the migration pain is real. Review every Python Code node you have.
4. ExecuteCommand and LocalFileTrigger: disabled by default
These nodes can execute system commands or watch local files, so n8n 2.0 disables them by default. Keep those exclusions unless a reviewed workflow needs a specific node.
NODES_EXCLUDE is the list of nodes not to load. An empty list enables all nodes; it is not a security setting to copy into every deployment. If you deliberately enable one node, remove only that node from your existing exclusion list and preserve the others. Node configuration.
5. OAuth Callbacks Need Authentication
N8N_SKIP_AUTH_ON_OAUTH_CALLBACK=false # New defaultBefore upgrading, test every OAuth integration. Slack, Google, whatever you've got connected—test it all.
6. File Operations Are Sandboxed
N8N_RESTRICT_FILE_ACCESS_TO=~/.n8n-files # New defaultReadWriteFile and ReadBinaryFiles nodes can only touch files in this directory now. Good for security, annoying if you've been reading files from random locations.
7. Configuration file permissions
n8n 2.0 enforces 0600 permissions on its settings file: only its owner can read or write it. Before upgrading, test with N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true and check the file's ownership and permissions in the environment where n8n actually runs.
The documented exception is an environment that cannot support these permissions, where enforcement can be disabled. A Windows host is not by itself a reason to disable the check inside a Linux container. Check the actual filesystem and mount behavior. Migration guidance.
Database Changes (The Painful Ones)
MySQL/MariaDB: Removed
Gone. PostgreSQL or SQLite only. This was deprecated in v1.0—if you're still on MySQL, that migration warning dates back to July 2023.
Use the database migration tool or you're screwed.
SQLite: Legacy Driver Removed
Only the pooling driver remains. It uses WAL mode and is the new default; n8n reported up to a 10× speedup in its benchmarks.
DB_SQLITE_POOL_SIZE=2 # Auto-configuredMost people won't notice this change. If you do, it's probably because something was broken before.
Binary Data: No More In-Memory Mode
The default mode that kept binary data in memory during execution? Gone.
Your options:
filesystem(default for single instance)database(default for queue mode)s3(if you're fancy)
Make sure you have disk space. If you're processing large files and suddenly run out of space, this is why.
Behavior Changes (The Subtle Ones)
Subworkflow + Wait Node = Fixed
Before: Parent workflow received input from Wait nodes in child workflows (which made no sense)
Now: Parent workflow receives output from the end of the child workflow (which is correct)
If you have workflows calling subworkflows with Wait nodes, review them. The behavior change is correct, but your logic might depend on the previous broken behavior.
Configuration Hell
dotenv Update
Your .env file parsing is different now.
Changes:
- Backticks need quotes now
- An unquoted
#starts a comment; wrap values containing#in quotes - Multi-line values work now
Review your .env files. Especially if you have weird characters in passwords or tokens.
Removed stuff:
QUEUE_WORKER_MAX_STALLED_COUNT- CLI option
n8n --tunnel(use ngrok or Cloudflare Tunnel) update:workflow --all --active=true(good riddance, this was dangerous)
Removed nodes:
- Spontit
- crowd.dev
- Kitemaker
Docker architecture for the 2.0 migration
The earlier examples mixed floating latest tags, example credentials and settings that re-enabled disabled nodes. They have been removed. This section explains the December 2025 migration; it is not a complete deployment recipe and has not been validated end to end.
Internal and external runners
| Mode | Arrangement | Scope |
|---|---|---|
| Internal | n8n starts the JavaScript runner as a child process | Isolated testing without sensitive data |
| External | A separate n8nio/runners container connects to the broker in n8n | Required for native Python; recommended with hardening for production |
From 2.0, the main n8n image no longer contains the external runner. The separate official runners image includes JavaScript and Python. Extra packages may require extending that image and configuring explicit allowlists; installing a package does not automatically make it available to Code nodes.
The broker connection
The direction matters: runner → broker in n8n, using the broker's private address on port 5679 by default. A single-instance deployment does not need Redis just because it uses external runners; queue mode has a separate Redis requirement.
| Setting | n8n container | Runner container |
|---|---|---|
N8N_RUNNERS_MODE | external | — |
N8N_RUNNERS_BROKER_LISTEN_ADDRESS | 0.0.0.0 when accepting connections from the private container network | — |
N8N_RUNNERS_TASK_BROKER_URI | — | Its broker address, such as http://n8n:5679 |
N8N_RUNNERS_AUTH_TOKEN | Securely generated shared token | The same token |
These are connection settings, not a Compose file. Keep the broker private, pin compatible n8n and runner images to the same version, and configure authentication, storage and proxying for your own environment. 1.111.0 is the documented minimum for this sidecar arrangement, not a current release recommendation. In queue mode, each worker needs a runner; main also needs one if it executes manual workflows.
Keep the default exclusions for ExecuteCommand and LocalFileTrigger. Review any custom exclusion list instead of replacing it with an empty list.
Implementation and validation
Use the official runner setup, runner variables and hardening guidance for the selected release. Check image compatibility, private broker reachability, matching authentication tokens, permissions and the dependencies used by your workflows.
Then test real JavaScript/Python Code nodes, OAuth callbacks, file operations, persistence and restart recovery in a separate environment. Container startup alone does not validate a migration. External containers improve separation; they do not guarantee protection against every malicious script, resource-exhaustion event or configuration error.
How Not to Screw This Up
Step 1: Check the migration report
Settings → Migration Report (you need admin access)
Available since v1.121.0. Run it now.
Step 2: Decide your runner mode
Using native Python Code nodes? → External mode is required. Production or sensitive data? → External mode plus hardening and validation. Isolated JavaScript testing without sensitive data? → Internal mode can be an option.
Step 3: If going external, generate token
openssl rand -hex 32Edit .env:
N8N_RUNNERS_AUTH_TOKEN=your-token-hereSet permissions:
chmod 600 .envStep 4: test the complete setup in staging
On a compatible 1.x version, enable task runners and test the new OAuth and file-permission defaults before migrating. On 2.0, runners are already enabled; verify the actual runner mode, broker connection and workflow behavior. Keep environment access blocked and the default node exclusions in place. A few environment variables do not replace testing the complete deployment.
Step 5: Review every Code node
Especially:
- Anything using
process.env - All Python Code nodes
- File operations
Step 6: Test OAuth
All integrations. Manually. No exceptions.
Step 7: Back up everything
Database, workflows, credentials, configs, complete .n8n directory.
Step 8: Help find bugs
Report bugs either in an issue on the repository or in the n8n community forum.
My Take
This is the most significant n8n release since 1.0. The security improvements are necessary.
For isolated testing, internal mode is simpler. For production or sensitive data, use the external runner setup and hardening guidance, and verify the whole workflow before migrating.
External mode is required for native Python and recommended with hardening for production. With queue workers, give each worker the runner setup it needs.
If you're running n8n in production (like I do every day), take this seriously. Budget real time for testing and migration. Don't just do docker pull and hope for the best.
The release adds useful security defaults and removes legacy components. Whether your migration is reliable depends on the configuration, workflows and recovery checks you actually test.

Discussion
Comments
No published comments