Claude Code generates, reviews, and optimizes workflows. n8n executes them. Together they create a complete automation platform: Claude handles intelligence, n8n handles execution.

Architecture: Brain + Engine

User Request
    ↓
Claude Code (Brain)        ← Understands intent, generates workflow
    ↓
n8n Workflow (Engine)      ← Executes the workflow reliably
    ↓
External Services          ← APIs, databases, email, Slack, etc
    ↓
Results Back to User

Claude Code doesn't execute workflows—it generates them. n8n handles the actual execution.

Why This Architecture?

Aspect Claude Code n8n
Reasoning Excellent Poor
Long Workflows Hard (token limits) Easy (persistent state)
Reliability Good, not guaranteed Excellent
Speed Slow (LLM latency) Fast (direct APIs)
Cost Per token Low, flat rate
Editing Workflows Natural language Visual + code

Combined: Claude generates smart workflows, n8n executes them reliably.

Pattern 1: Webhook-Triggered Automation

User requests Claude → Claude generates workflow → n8n executes

Step 1: User sends request to Claude
"Create an email digest of Slack messages from #general over the past week"

Step 2: Claude generates n8n workflow JSON
{
  "nodes": [
    {
      "name": "Slack List Messages",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "channel": "general",
        "limit": 100
      }
    },
    {
      "name": "Filter Last Week",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "return items.filter(msg => msg.ts > Math.floor(Date.now()/1000) - 604800)"
      }
    },
    {
      "name": "Email Digest",
      "type": "n8n-nodes-base.emailSend",
      "parameters": {
        "to": "[email protected]",
        "subject": "Weekly Digest",
        "body": "=new messages | map(...)"
      }
    }
  ]
}

Step 3: Claude uploads workflow to n8n via API
POST /api/v1/workflows
Authorization: Bearer [API_KEY]
Body: [workflow JSON]

Step 4: n8n stores workflow, ready to use
User can run it manually or schedule it

Step 5: n8n executes workflow, sends digest
Results saved to database, sent to user

Pattern 2: Workflow Generation from Requirements

User describes automation, Claude generates n8n workflow:

# claude_workflow_generator.py
from anthropic import Anthropic

def generate_workflow(requirement: str, context: dict) -> dict:
    """Generate n8n workflow from natural language requirement"""

    client = Anthropic()

    # Provide Claude with n8n JSON schema
    system_prompt = """You are an n8n workflow generator.
    Given user requirements, generate valid n8n workflow JSON.

    Available nodes: Slack, Gmail, HTTP, Code, Spreadsheet, Database, etc.
    Format output as valid JSON that can be imported into n8n.
    Include proper error handling and data transformation.
    """

    response = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=4096,
        system=system_prompt,
        messages=[
            {
                "role": "user",
                "content": f"""Generate n8n workflow for:
                {requirement}

                Context:
                - n8n instance: {context.get('n8n_url')}
                - Available APIs: {', '.join(context.get('apis', []))}
                - Database: {context.get('database_type')}

                Output: Valid n8n workflow JSON only (no markdown, no explanation)"""
            }
        ]
    )

    # Parse JSON response
    import json
    workflow_json = json.loads(response.content[0].text)

    return workflow_json

# Usage
requirement = """
Monitor GitHub issues labeled 'bug'.
For each new issue, create a Slack message in #bugs.
Include issue title, description, and link.
"""

workflow = generate_workflow(requirement, {
    "n8n_url": "http://n8n.example.com",
    "apis": ["github", "slack"],
    "database_type": "postgresql"
})

# Upload to n8n
upload_workflow_to_n8n(workflow)

Pattern 3: Workflow Review & Optimization

Generate workflow → Have Claude review it → Optimize

def review_and_optimize_workflow(workflow_json: dict) -> dict:
    """Have Claude review and optimize n8n workflow"""

    client = Anthropic()

    response = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=2048,
        messages=[
            {
                "role": "user",
                "content": f"""Review this n8n workflow and suggest optimizations:

{json.dumps(workflow_json, indent=2)}

Check for:
1. Unnecessary steps (can 2 nodes be combined?)
2. Missing error handling
3. Performance issues (batching, caching)
4. Security issues (hardcoded credentials, exposed data)
5. Cost optimization (API limits, expensive operations)

Output: Specific suggestions with code fixes"""
            }
        ]
    )

    suggestions = response.content[0].text
    print("Workflow Review:")
    print(suggestions)

    return workflow_json

Pattern 4: Email Processing Automation

Email arrives → n8n triggers Claude → Claude reads content → Claude generates response → n8n sends back

Setup

  1. Configure Webhook in n8n:
{
  "nodes": [
    {
      "name": "Email Trigger",
      "type": "n8n-nodes-base.webhookTrigger",
      "parameters": {
        "httpMethod": "POST",
        "path": "email-processor"
      }
    }
  ]
}
  1. Call Claude from n8n:
// In n8n Code node
const emailBody = $input.first().json.body;

// Call Claude API
const response = await fetch('https://api.anthropic.com/v1/messages', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.ANTHROPIC_API_KEY,
    'content-type': 'application/json'
  },
  body: JSON.stringify({
    model: 'claude-3-5-sonnet-20241022',
    max_tokens: 1024,
    messages: [
      {
        role: 'user',
        content: `Email: ${emailBody}\n\nRespond with a helpful reply.`
      }
    ]
  })
});

const result = await response.json();
return { reply: result.content[0].text };
  1. Send Reply:
{
  "name": "Email Reply",
  "type": "n8n-nodes-base.emailSend",
  "parameters": {
    "to": "={{ $json.from }}",
    "subject": "Re: {{ $json.subject }}",
    "body": "={{ $json.reply }}"
  }
}

Pattern 5: Content Processing Pipeline

Raw content → Extract (Claude) → Transform (Code) → Publish (HTTP) → Store (DB)

Workflow

# content-pipeline.json
nodes:
  - name: Get Content
    type: HTTP
    url: "https://api.example.com/articles"

  - name: Extract Key Points
    type: Code (Claude)
    prompt: "Summarize article in 3 bullet points"

  - name: Generate Social Post
    type: Code (Claude)
    prompt: "Create Twitter post for article"

  - name: Save to Database
    type: Database
    query: "INSERT INTO posts (content, summary, twitter_post)"

  - name: Post to Social
    type: Twitter
    action: "tweet"
    content: "={{ $json.twitter_post }}"

Pattern 6: Automated Testing

Code changes → Claude analyzes → Generate tests → n8n runs tests → Report results
def auto_test_workflow(code_diff: str) -> dict:
    """Generate and run tests for code changes"""

    client = Anthropic()

    # 1. Claude analyzes what changed
    analysis = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": f"What should be tested in this code change?\n\n{code_diff}"
            }
        ]
    )

    test_cases = analysis.content[0].text

    # 2. Claude generates test code
    generation = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=2048,
        messages=[
            {
                "role": "user",
                "content": f"Generate pytest tests for these cases:\n\n{test_cases}"
            }
        ]
    )

    test_code = generation.content[0].text

    # 3. n8n runs tests
    import subprocess
    result = subprocess.run(
        ["pytest", "-v"],
        input=test_code,
        capture_output=True,
        text=True
    )

    return {
        "test_code": test_code,
        "result": result.stdout,
        "passed": result.returncode == 0
    }

Pattern 7: Customer Support Automation

Support ticket → Claude categorizes → Route to specialist → Track resolution

Workflow Nodes

{
  "name": "Ticket Received",
  "type": "Webhook"
}

{
  "name": "Classify Ticket",
  "type": "Code (Claude)",
  "prompt": "Classify: urgent/normal/low. Category: billing/technical/general"
}

{
  "name": "Route",
  "type": "Switch",
  "cases": [
    {"category": "billing", "assignee": "finance-team"},
    {"category": "technical", "assignee": "engineering"},
    {"category": "general", "assignee": "support"}
  ]
}

{
  "name": "Draft Response",
  "type": "Code (Claude)",
  "prompt": "Draft helpful response to customer"
}

{
  "name": "Send Reply",
  "type": "Email"
}

{
  "name": "Track SLA",
  "type": "Database",
  "query": "INSERT INTO tickets (id, category, status, response_sent_at)"
}

Self-Hosted Setup (GDPR Compliant)

For EU customers, self-host both Claude Code and n8n:

Docker Compose

version: '3.8'

services:
  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    ports:
      - "5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD}
      - DB_TYPE=postgres
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${DB_PASSWORD}
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      - postgres

  postgres:
    image: postgres:15
    container_name: n8n-postgres
    environment:
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=n8n
    volumes:
      - postgres_data:/var/lib/postgresql/data

  claude-code-bridge:
    build: ./claude-code-bridge
    container_name: claude-bridge
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
      - N8N_URL=http://n8n:5678
      - N8N_API_KEY=${N8N_API_KEY}
    ports:
      - "8000:8000"

volumes:
  n8n_data:
  postgres_data:

Bridge Service (Claude API → n8n)

# claude-code-bridge/main.py
from fastapi import FastAPI, HTTPException
from anthropic import Anthropic
import httpx
import json

app = FastAPI()
client = Anthropic()

@app.post("/generate-workflow")
async def generate_workflow(request: dict):
    """Generate n8n workflow from Claude"""

    requirement = request.get("requirement")
    n8n_url = os.environ["N8N_URL"]
    api_key = os.environ["N8N_API_KEY"]

    # Claude generates workflow
    response = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=4096,
        messages=[
            {
                "role": "user",
                "content": f"Generate n8n workflow JSON for: {requirement}"
            }
        ]
    )

    workflow_json = json.loads(response.content[0].text)

    # Upload to n8n
    async with httpx.AsyncClient() as http_client:
        result = await http_client.post(
            f"{n8n_url}/api/v1/workflows",
            headers={"X-N8N-API-KEY": api_key},
            json=workflow_json
        )

    return {
        "workflow_id": result.json()["id"],
        "status": "created"
    }

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Security Considerations

Credential Management

# n8n credentials (never hardcode!)
{
  "credentials": {
    "slack_api_key": "{{ $env.SLACK_API_KEY }}",
    "github_token": "{{ $env.GITHUB_TOKEN }}",
    "database_url": "{{ $env.DATABASE_URL }}"
  }
}

Store credentials in environment variables or n8n's encrypted credential storage.

API Rate Limiting

# Prevent Claude from overwhelming APIs
class RateLimiter:
    def __init__(self, max_calls: int, time_window: int):
        self.max_calls = max_calls
        self.time_window = time_window
        self.calls = []

    def is_allowed(self) -> bool:
        now = time.time()
        self.calls = [c for c in self.calls if c > now - self.time_window]
        if len(self.calls) < self.max_calls:
            self.calls.append(now)
            return True
        return False

Data Privacy

For EU customers (GDPR compliance):

# Encrypt sensitive data in n8n
{
  "name": "Encrypt Data",
  "type": "Code",
  "code": """
  const crypto = require('crypto');
  const key = Buffer.from(process.env.ENCRYPTION_KEY);
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
  let encrypted = cipher.update(JSON.stringify($json), 'utf8', 'hex');
  encrypted += cipher.final('hex');
  return { encrypted, iv: iv.toString('hex') };
  """
}

Common Patterns Summary

Pattern Use Case Tools
Webhook + Claude Generate workflow on demand Claude + n8n
Scheduled Workflow Daily/weekly automation n8n cron
Email Processing Auto-respond, categorize n8n + Claude
Content Pipeline Extract, transform, publish Claude + n8n + APIs
Testing Generate tests for code Claude + n8n + pytest
Support Categorize tickets, draft replies Claude + n8n + email

Checklist

  • Set up n8n instance (cloud or self-hosted)
  • Created bridge service to connect Claude Code + n8n
  • Wrote workflow generation script with Claude API
  • Tested webhook triggers (email, GitHub, Slack, HTTP)
  • Implemented error handling in workflows
  • Added data transformation (code nodes)
  • Set up proper credential storage (not hardcoded)
  • Implemented rate limiting on API calls
  • Tested workflow review/optimization with Claude
  • Set up monitoring (workflow executions, errors)
  • Configured backups (workflow definitions, database)
  • Documented workflow patterns for team
  • Verified GDPR compliance (if EU customers)
  • Created admin dashboard for workflow management
  • Tested end-to-end automation (Claude → n8n → Results)