Build N8N Workflows with Claude Code 2026

Written by Michael Lip · Solo founder of Zovo · $400K+ on Upwork · 100% JSS Join 50+ builders · More at zovo.one

The Workflow

Generate complete N8N workflow JSON files using Claude Code, eliminating manual node-by-node assembly in the N8N editor. This approach suits developers who want version-controlled, reproducible automation pipelines that can be imported directly into N8N instances.

Expected time: 15-30 minutes per workflow Prerequisites: N8N instance (self-hosted or cloud), Claude Code installed, basic understanding of N8N node types

Setup

1. Create a Project Directory for N8N Workflows

mkdir -p ~/n8n-workflows && cd ~/n8n-workflows

This gives Claude Code a dedicated workspace for generating and managing workflow JSON files.

2. Add a CLAUDE.md with N8N Context

# CLAUDE.md

## Project Context
This directory contains N8N workflow JSON files for export/import.

## Rules
- All workflows must use N8N v1.x JSON schema
- Every node must have a unique name and valid position coordinates
- Credentials must use reference IDs, never inline secrets
- Webhook nodes must specify httpMethod and path
- Error handling: every workflow needs an Error Trigger node
- Position nodes on a grid: x increments of 250, y increments of 150

This ensures Claude generates valid, importable workflow files every time.

3. Verify N8N CLI Access

n8n --version
# Expected output:
# 1.64.0 (or your installed version)

If using N8N cloud, verify API access instead:

curl -s -H "X-N8N-API-KEY: $N8N_API_KEY" \
  https://your-instance.app.n8n.cloud/api/v1/workflows | jq '.data | length'
# Expected output: number of existing workflows

Usage Example

Ask Claude Code to generate a webhook-triggered workflow that receives form data, validates it, stores it in a database, and sends a Slack notification:

{
  "name": "Form Submission Handler",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "form-submit",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "webhook-1",
      "name": "Webhook Receiver",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [250, 300]
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.body.email }}",
              "operation": "isNotEmpty"
            },
            {
              "value1": "={{ $json.body.name }}",
              "operation": "isNotEmpty"
            }
          ]
        }
      },
      "id": "if-1",
      "name": "Validate Fields",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [500, 300]
    },
    {
      "parameters": {
        "operation": "insert",
        "table": "submissions",
        "columns": "name,email,message,created_at",
        "fieldsUi": {
          "fieldValues": [
            { "column": "name", "value": "={{ $json.body.name }}" },
            { "column": "email", "value": "={{ $json.body.email }}" },
            { "column": "message", "value": "={{ $json.body.message }}" },
            { "column": "created_at", "value": "={{ $now.toISO() }}" }
          ]
        }
      },
      "id": "postgres-1",
      "name": "Store in Database",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [750, 200],
      "credentials": {
        "postgres": { "id": "1", "name": "Production DB" }
      }
    },
    {
      "parameters": {
        "channel": "#form-submissions",
        "text": "New submission from {{ $json.body.name }} ({{ $json.body.email }})",
        "otherOptions": {}
      },
      "id": "slack-1",
      "name": "Notify Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [1000, 200],
      "credentials": {
        "slackApi": { "id": "2", "name": "Workspace Bot" }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ success: false, error: 'Missing required fields' }) }}"
      },
      "id": "respond-error",
      "name": "Error Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [750, 450]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ success: true }) }}"
      },
      "id": "respond-ok",
      "name": "Success Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [1250, 200]
    }
  ],
  "connections": {
    "Webhook Receiver": {
      "main": [[{ "node": "Validate Fields", "type": "main", "index": 0 }]]
    },
    "Validate Fields": {
      "main": [
        [{ "node": "Store in Database", "type": "main", "index": 0 }],
        [{ "node": "Error Response", "type": "main", "index": 0 }]
      ]
    },
    "Store in Database": {
      "main": [[{ "node": "Notify Slack", "type": "main", "index": 0 }]]
    },
    "Notify Slack": {
      "main": [[{ "node": "Success Response", "type": "main", "index": 0 }]]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}

Import the generated workflow:

# Import via CLI
n8n import:workflow --input=form-submission-handler.json

# Or via API
curl -X POST "https://your-instance.app.n8n.cloud/api/v1/workflows" \
  -H "X-N8N-API-KEY: $N8N_API_KEY" \
  -H "Content-Type: application/json" \
  -d @form-submission-handler.json

Common Issues

Why This Matters

Version-controlled N8N workflows enable reproducible automation across environments. Generating workflow JSON with Claude Code reduces a 30-minute drag-and-drop session to a 2-minute prompt.