n8n Workflows skill for Claude Code

n8n automations that retry safely and report failures. Claude builds n8n workflows item by item with pinned test data, dedupes webhook deliveries, sets per-node retries and an error workflow that posts the execution link, and keeps secrets in credentials only. It knows the 2.x save-versus-publish model and new defaults, exports workflows to git, and self-hosts with Postgres, external task runners and a backed-up encryption key.

  • namen8n-workflows
  • size191 lines · ≈2,300 tokens
  • files1
  • licenseMIT
  • updated

What Claude sees before loading it

This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.

description: Builds and operates n8n workflows that survive production — trigger choice, item-based data flow and expressions, credentials, retries and error workflows, idempotent webhooks, sub-workflows, Code nodes, version control via export, and self-hosting with Docker, Postgres, queue mode, task runners, and the 2.x save-versus-publish model. Use when creating or debugging an n8n workflow, wiring webhooks or schedules in n8n, handling n8n errors and retries, self-hosting or upgrading n8n, or reviewing a workflow JSON export.

Try asking

  • Build an n8n workflow that takes Stripe webhooks and creates HubSpot deals without duplicates
  • Set up self-hosted n8n on my VPS with Postgres, HTTPS and backups
  • My n8n workflow changes are not taking effect after I save them, what is wrong?

Use it when

  • Creating or debugging an n8n workflow
  • Webhooks in n8n fire twice or fail silently
  • Self-hosting, scaling or upgrading n8n
  • Putting n8n workflows under version control

Skip it when

How to check the result

Firing the same event twice yields one side effect, a forced failure triggers the error workflow with the execution link, and exported JSON contains no secrets.

The common mistake it prevents

Losing N8N_ENCRYPTION_KEY during a migration, which leaves every stored credential undecryptable.

~/.claude/skills/n8n-workflows/SKILL.md

--- name: n8n-workflows description: Builds and operates n8n workflows that survive production — trigger choice, item-based data flow and expressions, credentials, retries and… license: MIT ---

Done well means: the workflow does the same thing on a retry as on the first run, every failure reaches a human through an error workflow, credentials live only in n8n’s credential store, the workflow JSON is in version control, and a self-hosted instance can be restored from backup with its encryption key.

Hard rules

  • Secrets go in Credentials, never in node parameters, expressions, Code nodes, or pinned data. Exported workflow JSON contains parameters and pinned data in plain text.
  • Every production workflow has an error workflow set (Workflow settings -> Error workflow) that notifies a channel with the execution URL.
  • Webhooks that cause side effects (create records, send messages, charge money) must deduplicate by an idempotency key; senders retry.
  • Back up N8N_ENCRYPTION_KEY with the database. Without it, every stored credential is unrecoverable.
  • Before deleting workflows or executions, or upgrading a major version, export workflows and back up the database, and confirm with the user.

Version notes (verify against the instance)

  • n8n 2.0 split Save from Publish: saving no longer changes the live version; the old Active toggle became Publish/Unpublish. Edits are not live until published.
  • 2.0 defaults: Code nodes run in task runners; Code-node access to environment variables is blocked (N8N_BLOCK_ENV_ACCESS_IN_NODE=true); Execute Command and Local File Trigger nodes are disabled by default; MySQL/MariaDB are no longer supported as the n8n database (use Postgres or SQLite); the Execute Workflow node returns the sub-workflow’s output.
  • Check the running version (Settings -> About, or n8n --version) and read the release’s breaking-changes page before upgrading across a major.

Workflow

- [ ] 1. Define trigger, inputs, outputs, side effects, and the failure policy
- [ ] 2. Build with pinned sample data; one concern per node
- [ ] 3. Add idempotency and input validation at the entry
- [ ] 4. Configure retries per node and an error workflow
- [ ] 5. Test with the test URL / manual run; then publish
- [ ] 6. Export to git; document credentials needed
- [ ] 7. Watch the first production executions

1. Triggers

NeedTriggerNotes
External system pushes eventsWebhook (or the app’s Trigger node)Test URL works only while “listening” in the editor; production URL works only when published
Fixed scheduleSchedule TriggerTimezone from workflow settings or GENERIC_TIMEZONE; mind DST
Poll an API with no webhooksSchedule + HTTP Request + dedupeTrack a cursor/high-water mark
Called by other workflowsExecute Workflow Trigger (sub-workflow)Define the input schema
Errors from other workflowsError TriggerOnly in a workflow used as an error workflow
Human input mid-flowForm Trigger / Wait node with resume webhookSet a timeout

Webhook security: require Header Auth or Basic Auth credentials on the Webhook node, or verify the provider’s HMAC signature in a Code node over the raw body (enable the raw body option). Respond quickly (Respond: Immediately) and do slow work after; most providers time out in 5-30 seconds and retry.

2. Data flow and expressions

  • n8n passes arrays of items; most nodes run once per item. Think in items, not one JSON.
  • Expressions: {{ $json.email }} (current item), {{ $('Get Customer').item.json.id }} (paired item from an earlier node), {{ $now.toISO() }}, {{ $env.MY_VAR }} only if env access is allowed for expressions on your instance.
  • Use Edit Fields (Set) to shape data explicitly between steps; keep only the fields the next node needs.
  • Split Out / Aggregate / Loop Over Items (batching) for large lists; batch API calls to respect rate limits, with a Wait node between batches if needed.
  • Pin data on the trigger while building so you do not refire real events; unpin before publishing and never pin data that contains personal data or secrets.

3. Idempotency

Patternn8n implementation
Dedupe repeated webhook deliveriesRemove Duplicates node with “remove items processed in previous executions” keyed on the event ID, or a lookup in your DB before acting
Upsert instead of insertUse the destination’s upsert/“create or update” operation keyed on a natural ID
PollingStore last cursor in a data table or DB; only advance after downstream success
Outbound messagesRecord (recipient, event ID) before sending; skip if present

4. Errors and retries

  • Node settings: Retry On Fail (e.g., 3 tries, 5000 ms wait) for network calls to flaky APIs. Do not retry non-idempotent calls without an idempotency key.
  • On Error: Stop Workflow (default, triggers the error workflow), Continue (passes the error as data; use only when you handle it), or Continue (using error output) to branch failures to a dedicated path.
  • Error workflow template: Error Trigger -> Edit Fields (workflow name, node, error message, {{ $json.execution.url }}) -> Slack/Email/Teams. Set it on every production workflow. Keep the error workflow simple so it cannot fail itself.
  • Use Stop and Error node to fail deliberately on validation errors (e.g., missing required field) with a clear message.

5. Code nodes

  • Prefer built-in nodes; use Code for transformations that would take five nodes.
  • JavaScript: “Run Once for All Items” returns an array of { json: {...} }; “Run Once for Each Item” returns one object. Python Code nodes need task runners in external mode on 2.x.
  • No secrets in code; read them through credentials (HTTP Request node with a credential) rather than env vars.

6. Version control

  • Enterprise/Business plans: built-in Source control (Git) with environments.
  • Otherwise export via CLI and commit:
n8n export:workflow --all --separate --output=workflows/    # one JSON file per workflow
n8n export:credentials --all --output=creds/                # encrypted; do NOT commit unless repo is private and key is separate
n8n import:workflow --separate --input=workflows/

In Docker: docker compose exec n8n n8n export:workflow --all --separate --output=/home/node/backup/. Review exports for pinned data and hardcoded values before committing.

Self-hosting (Docker Compose essentials)

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n:<pinned-version>
    restart: unless-stopped
    ports: ["127.0.0.1:5678:5678"]          # put a TLS reverse proxy in front
    environment:
      - N8N_HOST=n8n.example.com
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.example.com/
      - GENERIC_TIMEZONE=UTC
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=336        # hours (14 days)
      - N8N_RUNNERS_MODE=external
      - N8N_RUNNERS_AUTH_TOKEN=${RUNNERS_TOKEN}
      - N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
    volumes: ["n8n_data:/home/node/.n8n"]
    depends_on: [postgres]
  task-runners:
    image: n8nio/runners:<same-version>
    environment:
      - N8N_RUNNERS_TASK_BROKER_URI=http://n8n:5679
      - N8N_RUNNERS_AUTH_TOKEN=${RUNNERS_TOKEN}
    depends_on: [n8n]
  postgres:
    image: postgres:16
    environment: [POSTGRES_USER=n8n, POSTGRES_PASSWORD=${POSTGRES_PASSWORD}, POSTGRES_DB=n8n]
    volumes: ["pg_data:/var/lib/postgresql/data"]
volumes: { n8n_data: {}, pg_data: {} }
  • Keep the .env with secrets out of git (mode 600). Pin image versions; n8n and runners versions must match.
  • WEBHOOK_URL must be the public URL or webhook URLs shown in the editor will be wrong behind a proxy.
  • Scale: queue mode (EXECUTIONS_MODE=queue + Redis + worker containers running n8n worker) when executions back up or long workflows block others.
  • Backups: nightly pg_dump plus the encryption key stored separately; test a restore.

Verification

  • Run with the test webhook / manual execution using realistic data; then fire the same event twice against production and confirm a single side effect.
  • Force a failure (bad credential or invalid input) and confirm the error workflow notifies with the execution link.
  • Confirm the workflow is published (2.x) and the production webhook URL responds.
  • Export JSON contains no secrets (grep -iE 'token|password|secret|apikey' workflows/*.json).

Gotchas

  • Editing a published workflow in 2.x does nothing live until you publish again; in 1.x, saving an active workflow changed production immediately.
  • Merge node behavior depends on mode (append, combine by key, by position); wrong mode silently drops or duplicates items.
  • Large binary data in executions bloats the database; set N8N_DEFAULT_BINARY_DATA_MODE=filesystem (or S3 on enterprise) and prune executions.
  • Schedule Trigger uses the workflow timezone setting; a mismatch with the server makes jobs fire an hour off after DST changes.
  • Community nodes run with n8n’s privileges; review them like any dependency.

About this skill

Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.

esc