n8n: nodes, expressions, CLI and settings in one place
Everything important about n8n on one page — concepts, nodes, expressions, the Code node, Docker, commands and environment variables. Checked against the official documentation for the 2.x line: from our old notes we removed what no longer exists (basic-auth login, "activating" workflows, Python through Pyodide).
N8N_BASIC_AUTH_* does not appear in the docs — on first open you create an owner account; "activate" is replaced by publish (n8n publish:workflow, while update:workflow is deprecated); Python in the Code node is now native Python (_items, bracket access), not Pyodide; WEBHOOK_URL is a deprecated alias of N8N_WEBHOOK_URL; the default EXECUTIONS_DATA_MAX_AGE is 336 hours, and Execute Command and Local File Trigger are off. Renamed nodes: Execute Workflow → Execute Sub-workflow, Window Buffer Memory → Simple Memory, HTML Extract → HTML. Removed because unconfirmed: n8n list:workflow, "F5 to pin", "Ctrl+D duplicates" (in the docs P pins data and D deactivates a node), a "JSON Parse" node, a 3-minute timeout for Respond to Webhook. Removed for privacy: the section about our internal machines and ports — replaced by a general network-protection rule.
01What you'll learn
This is a reference, not a step-by-step lesson — so section 03 is laid out as "task → answer" cards. You will find:
- The core concepts: workflow, node, item, execution, credentials, expression.
- Which nodes exist — triggers, actions, flow, AI and utility — and which are off by default in 2.x.
- How to write expressions and what to use in the Code node (JavaScript and native Python).
- How to install with Docker, how to manage it (logs, restart, updates) and which CLI commands are current.
- Which environment variables matter, and how to turn on queue mode.
- A short "symptom → cause → fix" table and where to read further.
02Before you start
What you need
- Docker with
docker composev2 for the install 🔒 local. On Windows the docs recommend WSL, with the project inside the WSL file system. - For a local model: Ollama 🔒 local. For services such as Gmail — an account with the provider 🌐 global.
- Versions change almost every week. As of 01.10.2026 the docs list stable 2.41.4 and beta 2.42.1. For production use the stable one.
docker.n8n.io/n8nio/n8n (the docs also show it as n8nio/n8n — the same product). The beta tag (old name next) is the unstable version, stable (old name latest) the stable one. In production pin a version instead of following "latest", and read the release notes before updating.npm install n8n / npx n8n no longer works and n8n is distributed through Docker only. An existing npm install keeps working for now, but new installs and future upgrades should use Docker. Version 1 of the AI Agent node is also removed in 3.0.<SECRET>. Do not expose n8n straight to the internet without HTTPS and a reverse proxy.03Steps
For a reference the "steps" are cards by task. Take the one you need.
-
Core concepts
Concept What it is Workflow A diagram of connected nodes that runs on a trigger or manually. Saved as JSON and can be exported/imported (see card 6). Node The building block: receives items, processes them and passes them on. Item A unit of data — one JSON object in the array a node passes on. Execution One run of a workflow. Stored in the database; visible in the Executions tab. By default both successful and failed runs are saved, and old ones are deleted after 336 hours (card 9). Credentials Encrypted access data. Encrypted with N8N_ENCRYPTION_KEY; one credential can serve many workflows.Expression A dynamic value in a field, written in {{ }}with JavaScript. In an empty field press = to switch to expression mode.Sub-workflow A workflow called from another through the Execute Sub-workflow node; it starts with an Execute Sub-workflow Trigger. Publishing In 2.x the old "active/inactive" toggle is replaced by Publish / Unpublish. Production webhook URLs are registered when you publish. -
Nodes: what to use for what
Names follow the current docs. Marker: [off] — disabled by default in 2.x (turn on through
NODES_EXCLUDE).Group Node What for Triggers Webhook HTTP request from an external system; has a test and a production URL Schedule Trigger On a schedule (cron or interval); the time zone is GENERIC_TIMEZONEEmail Trigger (IMAP) New email in a mailbox Gmail Trigger New message in Gmail Chat Trigger Built-in chat — for AI agents Execute Sub-workflow Trigger Called from another workflow Manual Trigger Manual start for building and checking Error Trigger · Local File Trigger [off] Catches errors from another workflow · watches changes in the file system Actions HTTP Request Calls a REST API Send Email Sends mail through SMTP Gmail Reads and sends through Gmail Read/Write File From Disk File access on the machine running n8n Postgres · Redis Queries to PostgreSQL · work with Redis SSH Commands on a remote machine Execute Command [off] Commands on the machine running n8n (in Docker — inside the container) Flow If · Switch Branch by condition · by value Merge Merges streams Loop Over Items (Split in Batches) Processes items in batches; has loop and done outputs Wait A pause Execute Sub-workflow Calls another workflow Respond to Webhook Returns a response to the webhook caller Stop and Error Stops with your own error message (sent to the Error Trigger) AI AI Agent An agent with a model and tools; requires at least one tool (tool sub-node) Basic LLM Chain One LLM call: prompt → answer Text Classifier · Sentiment Analysis · Information Extractor Classifies · scores tone · pulls structured data out of text Summarization Chain Summarises long text Ollama Chat Model A local model through Ollama 🔒 local Embeddings Ollama Vector embeddings locally 🔒 local Simple Memory Short-term agent memory (formerly "Window Buffer Memory") Qdrant Vector Store · Simple Vector Store Vector store (external · in memory) MCP Client Tool Gives the agent tools from an MCP server Utility Code JavaScript or Python (card 5) Edit Fields (Set) Adds, renames, reorders fields without code Filter · Sort · Limit Filter by condition · sort · first N Remove Duplicates Removes repeated items Aggregate · Summarize Collects items into one · groups and calculates (sum, count) HTML · Markdown Extracts data from HTML with CSS selectors · converts HTML ↔ Markdown Crypto Hash and signature Date & Time Formats and calculates dates Edit Image Image processing 💡You often do not need a loopMost nodes already process every item in the list. Loop Over Items is for cases where you need batches or a pause between requests (for example because of API limits). If you build a loop withreset, always add an end condition — otherwise the execution loops forever. -
Expressions: reference
Expression Meaning {{ $json.field }}A field of the current item {{ $json["field name"] }}A field with a space in its name {{ $json.user.email }}·{{ $json.tags[0] }}Nested field · first element of an array {{ $input.first().json.id }}The first input item (also .last(),.all()){{ $input.all().length }}Number of input items {{ $('Node Name').item.json.x }}Data from a specific node for the matching item {{ $('Node Name').all() }}All items that node output (also .first(),.last()){{ $prevNode.name }}The name of the node the data came from {{ $workflow.name }}·{{ $execution.id }}Workflow name · execution ID {{ $now }}·{{ $today }}Now (Luxon DateTime, in the workflow time zone) · midnight today {{ $if(condition, if_true, if_false) }}·{{ $ifEmpty(value, fallback) }}Short conditionals {{ $vars.name }}·{{ $fromAI('key') }}Custom variable · a value the model fills in (in agent tools) expressions// dates (Luxon) {{ $now.toFormat('dd.MM.yyyy') }} {{ $now.plus({ days: 7 }).toISO() }} {{ DateTime.fromISO($json.createdAt).toFormat('dd.MM.yyyy') }} // condition {{ $json.amount > 1000 ? 'VIP' : 'Standard' }} // text and numbers {{ $json.email.split('@')[0] }} {{ [$json.firstName, $json.lastName].join(' ') }} {{ Math.round($json.price * 1.2) }} // JSON for a request body {{ JSON.stringify($json) }} // fallback value {{ $json.name ?? 'Unknown' }}💡Expressions and the Code node are not the same thingSome helpers ($if(),$jmespath()and others) work only in the expression editor, not in the Code node. Methods tagged "Custom n8n functionality" in the reference may be missing there — use native Luxon (toFormat) and plain JavaScript. Note:plus()/minus()in expressions accept(number, unit)or an object, while native Luxon accepts only an object. -
Data flow: Webhook, response and errors
Webhook → process → respond. In the Webhook node set Respond to "Using 'Respond to Webhook' node", then place Respond to Webhook after the nodes whose data you return. It runs once, with the first item.
Webhook → If (validation) → Code / Edit Fields → Postgres (write) → Respond to Webhook- The test URL works while you listen for an event (Listen for test event) and shows the data in the editor. Path:
/webhook-test/<path>. - The production URL is registered when you publish the workflow; runs show up in Executions. Path:
/webhook/<path>. - The largest request body is 16 MiB by default (
N8N_PAYLOAD_SIZE_MAX). - An HTML response is wrapped in an
<iframe>automatically (since 1.103.0) — scripts that reach for the top-level window will not work.
Errors. Build a separate workflow that starts with an Error Trigger (for example "Error Handler"). In the main workflow: Options → Settings → Error workflow and pick it. The Error Trigger cannot be tested with a manual run — it fires only when an automatically started workflow fails. Stop and Error sends a custom message to it.
Schedule → fetch → notify: Schedule Trigger → HTTP Request → Filter (new only) → Loop Over Items → Send Email. AI pipeline: Webhook or Email Trigger → Edit Fields (prepare the prompt) → AI Agent (with a model and a tool) → write.
- The test URL works while you listen for an event (Listen for test event) and shows the data in the editor. Path:
-
The Code node: JavaScript and native Python
Two modes: Run Once for All Items (the default — the code runs once for everything) and Run Once for Each Item. Inside, there is no file or HTTP access — use Read/Write File From Disk and HTTP Request.
JavaScript · all itemsconst out = []; for (const item of $input.all()) { out.push({ json: { fullName: item.json.firstName + ' ' + item.json.lastName, processedAt: new Date().toISOString(), }, }); } return out; // filtering // return $input.all().filter(i => i.json.status === 'active'); // everything in one item // return [{ json: { all: $input.all().map(i => i.json) } }];Python (native) · all itemsresult = [] for item in _items: data = item["json"] result.append({"json": { "id": data["id"], "total": data["price"] * data["qty"], }}) return result🐍Python in 2.x: what changedThe old Pyodide-based Python is removed. Native Python runs only on task runners in external mode (the separaten8nio/runnersimage), uses_items(all) and_item(one at a time), field access is only["json"]["field"](notitem.json.field), and the other n8n built-in variables are not available. Modules beyond the standard library must be included in the runners image.⚠️Environment variables from the Code node ⚠️The 2.0 notes say access to environment variables from the Code node is blocked by default (N8N_BLOCK_ENV_ACCESS_IN_NODE), but the variables table still shows a default offalse. Do not rely on either: for secrets use credentials, not environment variables.$evaluateExpression()no longer works in the Code node — write the logic directly in JavaScript, or evaluate the expression in Edit Fields before the Code node. -
Installing and managing with Docker
Fastest (fresh install; read the script before running it; needs Docker with
composev2):bashcurl -fsSL https://get.n8n.io | shManually, for trying it out only (data lives in the
n8n_datavolume; the editor is athttp://localhost:5678):bashdocker volume create n8n_data docker run -it --rm --name n8n -p 5678:5678 \ -e GENERIC_TIMEZONE="<TIMEZONE>" \ -e TZ="<TIMEZONE>" \ -e N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true \ -v n8n_data:/home/node/.n8n \ docker.n8n.io/n8nio/n8nThe first time, n8n asks you to create an owner account — that is how you log in (basic auth with
N8N_BASIC_AUTH_*does not appear in the docs).N8N_RUNNERS_ENABLEDis no longer needed from 2.0.A compose file template with PostgreSQL ⚠️ (assembled from the variables in the docs; not run by us — the official examples are in the
n8n-io/n8n-hostingrepository):compose.ymlservices: n8n: image: docker.n8n.io/n8nio/n8n:<VERSION> restart: unless-stopped ports: - "5678:5678" environment: - GENERIC_TIMEZONE=<TIMEZONE> - TZ=<TIMEZONE> - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true - N8N_ENCRYPTION_KEY=<SECRET> - N8N_HOST=<YOUR-DOMAIN> - N8N_PROTOCOL=https - N8N_WEBHOOK_URL=https://<YOUR-DOMAIN>/ - DB_TYPE=postgresdb - DB_POSTGRESDB_HOST=<DB-HOST> - DB_POSTGRESDB_DATABASE=<DATABASE> - DB_POSTGRESDB_USER=<USER> - DB_POSTGRESDB_PASSWORD=<SECRET> volumes: - n8n_data:/home/node/.n8n volumes: n8n_data:Even with PostgreSQL keep the
/home/node/.n8nvolume — keys, logs and other important files are there. WithoutN8N_ENCRYPTION_KEYn8n generates a key itself on first start; if you set one, keep it somewhere safe — without it saved credentials cannot be read.bash · managingdocker ps docker logs -f --tail=100 n8n docker restart n8n docker stats n8n # update (compose) docker compose pull docker compose down docker compose up -d # update (docker run): pull the image, stop and remove the old container, start again docker pull docker.n8n.io/n8nio/n8n -
CLI and REST API
The Server CLI runs on the same machine as n8n and touches the database directly. In Docker:
docker exec -u node -it <container> n8n <command>.bash · Server CLIn8n execute --id <ID> # publishing (replaces update:workflow since 2.0) n8n publish:workflow --id=<ID> n8n unpublish:workflow --id=<ID> # backup of workflows and credentials n8n export:workflow --backup --output=backups/latest/ n8n export:credentials --backup --output=backups/latest/ # restore n8n import:workflow --separate --input=backups/latest/ n8n import:credentials --separate --input=backups/latest/ # security check n8n auditpublish:workflow/unpublish:workflowtouch the database — if n8n is running, the change takes effect after a restart. There is no--allfor publishing (on purpose), but there is one forunpublish.update:workflowis deprecated since 2.0. We could not findn8n list:workflowin the current docs — do not rely on it.export:credentials --decryptedwrites secrets as plain text — use it only for a deliberate transfer and then delete the file securely.- Imported workflows stay inactive by default (
--activeState=false). --backupcovers workflows and credentials only; a full instance backup has more parts — see "Back up and restore" in the docs.
REST API (from another machine): a key from Settings → n8n API, sent in the
X-N8N-API-KEYheader. The API is not available during the n8n Cloud free trial.bash · REST and healthcurl 'https://<YOUR-N8N>/api/v1/workflows?active=true' \ -H 'accept: application/json' \ -H 'X-N8N-API-KEY: <API-KEY>' # call a production webhook curl -X POST 'https://<YOUR-N8N>/webhook/<PATH>' \ -H 'Content-Type: application/json' \ -d '{"key": "value"}' # liveness check curl -sf 'https://<YOUR-N8N>/healthz' -
Keyboard shortcuts (per the docs)
Group Shortcuts Workflow Ctrl/Cmd+S save · Ctrl/Cmd+Z undo · Ctrl/Cmd+Shift+Z redo · Ctrl/Cmd+Enter execute · Ctrl/Cmd+Alt+N new · Ctrl/Cmd+O open Canvas Space+drag or middle button — pan · +/- zoom · 0 reset zoom · 1 fit the workflow · Ctrl/Cmd+wheel zoom Nodes N node panel · Ctrl/Cmd+A all · Ctrl/Cmd+C/X/V · F2 rename · P pin data · D deactivate · Delete delete · Shift+S sticky note Other Ctrl/Cmd+K command bar · Escape closes the node panel Running the "whole workflow" and "this node only" are separate buttons in the editor; pinning data freezes a node's output while you build.
-
Environment variables and queue mode
Variable Meaning N8N_HOST·N8N_PORT·N8N_PROTOCOLThe host name, port (5678) and protocol ( http/https) used to reach n8nN8N_WEBHOOK_URLBase URL of webhooks behind a reverse proxy; must be reachable from outside. WEBHOOK_URLis a deprecated alias (since 2.35.0)N8N_EDITOR_BASE_URL·N8N_PROXY_HOPSPublic editor URL (for emails and SSO) · how many reverse proxies sit in front GENERIC_TIMEZONE·TZn8n's time zone (default America/New_York!) — matters for schedules · container clockN8N_ENCRYPTION_KEYKey that encrypts credentials; generated automatically by default. Keep it; in queue mode it is the same everywhere DB_TYPEpostgresdbfor production · SQLite by default. MySQL/MariaDB are not supported since 2.0N8N_LOG_LEVELinfo(default) ·warn·error·debugEXECUTIONS_DATA_PRUNE·EXECUTIONS_DATA_MAX_AGEClean up old executions (on by default) · age in hours (default 336 = 14 days) EXECUTIONS_DATA_SAVE_ON_SUCCESS/_ON_ERRORallornone; everything is saved by defaultN8N_METRICStrueturns on the/metricsendpoint (off by default)N8N_PAYLOAD_SIZE_MAXLargest request body in MiB (16) N8N_DISABLE_UItruedisables the editorNODES_EXCLUDEWhich nodes are disabled; Execute Command and Local File Trigger are there by default N8N_ENFORCE_SETTINGS_FILE_PERMISSIONStruesets 0600 permissions on the settings fileQueue mode (many workers): the main instance receives triggers and webhooks and puts executions in a queue in Redis; workers pick them up and run them.
- Redis (
QUEUE_BULL_REDIS_HOST,QUEUE_BULL_REDIS_PORT, default 6379) and PostgreSQL — SQLite with queue mode is not recommended. EXECUTIONS_MODE=queueon the main instance and on every worker; the sameN8N_ENCRYPTION_KEYeverywhere.- Worker:
n8n worker(--concurrency=N, default 10; 5 or more recommended). Optional: separate webhook processes withn8n webhook. - Binary data in the file system is not supported in queue mode — use external storage (S3).
🛡️Network protection — a general ruleRun n8n behind a reverse proxy with HTTPS; only the editor entrance and webhooks should be visible from outside — not the database, Redis or workers. Addresses and ports of a specific installation do not belong on pages like this one. - Redis (
-
Quick diagnostics: symptom → cause → fix
Symptom Likely cause Fix The production webhook does not respond The workflow is not published (only the test URL works) Publish it; use /webhook/…, not/webhook-test/…The webhook shows a wrong address behind a proxy n8n does not know its external address Set N8N_WEBHOOK_URL(andN8N_PROXY_HOPS)The schedule fires at the wrong hour The zone is the default America/New_YorkSet GENERIC_TIMEZONE(andTZ)After a move, credentials cannot be read A different N8N_ENCRYPTION_KEYRestore the old key; in queue mode — the same on all instances No Execute Command or Local File Trigger node Disabled by default since 2.0 Change NODES_EXCLUDE— only if you understand the riskPython in the Code node does not start or complains about item.jsonNative Python needs task runners in external mode and bracket access Run the n8nio/runnersimage; use_itemsanditem["json"]$evaluateExpression()in Code returnsnullNot supported with task runners Write the logic in JavaScript or evaluate the expression in Edit Fields before Code The error workflow does not fire in a manual test The Error Trigger runs only from an automatic execution Test through a trigger or a published workflow CLI publishing has no effect n8n is running while the CLI writes to the database Restart n8n A webhook request is rejected for size Over 16 MiB Raise N8N_PAYLOAD_SIZE_MAX(with more memory and CPU)The database keeps growing All executions are saved Keep EXECUTIONS_DATA_PRUNEon and lowerEXECUTIONS_DATA_MAX_AGE
04Check
Checklist
- You know you are on the 2.x line: publish instead of activate, native Python, login with an owner account.
N8N_ENCRYPTION_KEYis stored somewhere safe and is the same on all workers.GENERIC_TIMEZONEis set before you rely on schedules.- Production webhooks work only after publishing; test ones are for building.
- Before queue mode you have PostgreSQL and Redis.
- Secrets are in credentials — not in fields, expressions or pages.
Quiz
1. How do you publish a workflow from the command line in 2.x?
2. In queue mode, what must be the same on the main instance and the workers?
3. Where should an API key for an external service live?
05What's next
06Sources
- n8n: one-line setup · install with Docker · with Docker Compose — image, volume, versions, n8n 3.0.
- Server CLI and REST API authentication —
publish:workflow,export/import,X-N8N-API-KEY. - What changes in 2.0 — publishing, native Python, disabled nodes, task runners.
- Environment variables — the Deployment, Endpoints, Executions, Queue mode, Security and Timezone sections.
- Queue mode — Redis, workers, the encryption key.
- Expression reference and the Code node.
- AI Agent · Webhook · Respond to Webhook · Error Trigger.
- Keyboard shortcuts.
- GitHub: n8n-io/n8n — quick start and the compose definition.