Skills n8n-workflow-sdk

install
source · Clone the upstream repo
git clone https://github.com/TerminalSkills/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/TerminalSkills/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/n8n-workflow-sdk" ~/.claude/skills/terminalskills-skills-n8n-workflow-sdk && rm -rf "$T"
manifest: skills/n8n-workflow-sdk/SKILL.md
safety · automated scan (low risk)
This is a pattern-based risk scan, not a security review. Our crawler flagged:
  • references .env files
  • references API keys
Always read a skill's source content before installing. Patterns alone don't mean the skill is malicious — but they warrant attention.
source content

n8n Workflow SDK

Overview

@n8n/workflow-sdk
is the official TypeScript SDK from n8n (v0.2.0, released February 2026) for programmatically creating, validating, and converting workflows. Instead of dragging nodes in the UI, define workflows as code — type-safe, version-controlled, and composable. Supports all n8n node types including AI/LangChain nodes. Includes bidirectional conversion between JSON and TypeScript.

Instructions

Step 1: Install and Create a Basic Workflow

npm install @n8n/workflow-sdk
// workflows/data-sync.ts — Programmatic workflow creation
import { WorkflowBuilder, manual, httpRequest, code } from '@n8n/workflow-sdk'

// Build a simple data sync workflow
const workflow = new WorkflowBuilder()
  .withName('Daily Data Sync')
  .addTrigger(manual())
  .then(httpRequest({
    url: 'https://api.example.com/users',
    method: 'GET',
    headers: {
      Authorization: '={{ $env.API_KEY }}',      // n8n expression for env variable
    },
  }))
  .then(code({
    language: 'typescript',
    code: `
      // Transform API response to internal format
      return items.map(item => ({
        json: {
          id: item.json.id,
          email: item.json.email,
          name: \`\${item.json.firstName} \${item.json.lastName}\`,
          active: item.json.status === 'active',
          syncedAt: new Date().toISOString(),
        }
      }))
    `,
  }))
  .build()

// workflow is now a valid n8n JSON object ready to import
console.log(JSON.stringify(workflow, null, 2))

Step 2: Control Flow — Branching and Merging

// workflows/lead-routing.ts — Conditional workflow with branches
import {
  WorkflowBuilder, webhook, ifElse, merge,
  httpRequest, node, sticky,
} from '@n8n/workflow-sdk'

const workflow = new WorkflowBuilder()
  .withName('Lead Routing')

  // Trigger on incoming webhook
  .addTrigger(webhook({
    path: 'new-lead',
    method: 'POST',
    responseMode: 'onReceived',
  }))

  // Branch based on lead score
  .then(ifElse({
    conditions: {
      combinator: 'and',
      conditions: [
        { leftValue: '={{ $json.score }}', operator: 'gte', rightValue: 80 },
      ],
    },
  }))

  // True branch — high-value lead → Salesforce + Slack notification
  .onTrue(
    httpRequest({
      url: 'https://mycompany.salesforce.com/api/leads',
      method: 'POST',
      body: '={{ JSON.stringify($json) }}',
    })
  )

  // False branch — low-score lead → add to nurture campaign
  .onFalse(
    httpRequest({
      url: 'https://api.mailchimp.com/3.0/lists/abc123/members',
      method: 'POST',
      body: '={{ JSON.stringify({ email_address: $json.email, status: "subscribed" }) }}',
    })
  )

  // Add documentation
  .addSticky(sticky({
    content: '## Lead Routing\nHigh-score leads (≥80) go to Salesforce.\nOthers enter nurture campaign.',
    width: 300,
    height: 150,
  }))

  .build()

Step 3: AI/LangChain Workflows

// workflows/ai-support-agent.ts — AI agent with tools and memory
import {
  WorkflowBuilder, webhook,
  languageModel, memory, tool, outputParser,
  node,
} from '@n8n/workflow-sdk'

const workflow = new WorkflowBuilder()
  .withName('AI Support Agent')

  .addTrigger(webhook({ path: 'support', method: 'POST' }))

  // AI Agent node with LangChain components
  .then(node('n8n-nodes-langchain.agent', {
    text: '={{ $json.message }}',
    systemMessage: `You are a helpful customer support agent for a SaaS product.
      Use the available tools to look up account information and
      knowledge base articles. Be concise and helpful.`,
  }))

  // Attach LLM
  .withSub(languageModel('openAi', {
    model: 'gpt-4o',
    temperature: 0.3,
  }))

  // Attach conversation memory
  .withSub(memory('windowBuffer', {
    sessionKey: '={{ $json.userId }}',
    windowSize: 20,      // remember last 20 messages
  }))

  // Attach tools the agent can use
  .withSub(tool('httpRequest', {
    name: 'lookup_account',
    description: 'Look up customer account by email or ID',
    url: 'https://api.myapp.com/accounts/{{ $fromAi("query") }}',
    method: 'GET',
  }))
  .withSub(tool('httpRequest', {
    name: 'search_knowledge_base',
    description: 'Search the knowledge base for help articles',
    url: 'https://api.myapp.com/kb/search?q={{ $fromAi("query") }}',
    method: 'GET',
  }))

  // Parse structured output
  .then(outputParser('structured', {
    schema: {
      answer: { type: 'string', description: 'The response to the customer' },
      category: { type: 'string', description: 'Issue category: billing, technical, general' },
      escalate: { type: 'boolean', description: 'Whether to escalate to human agent' },
    },
  }))

  .build()

Step 4: Batch Processing with Split and Merge

// workflows/bulk-enrichment.ts — Process records in batches
import {
  WorkflowBuilder, schedule, httpRequest,
  splitInBatches, merge, code, node,
} from '@n8n/workflow-sdk'

const workflow = new WorkflowBuilder()
  .withName('Contact Enrichment Pipeline')

  // Run every night at 2 AM
  .addTrigger(schedule({ rule: { interval: [{ field: 'hours', triggerAtHour: 2 }] } }))

  // Fetch contacts that need enrichment
  .then(httpRequest({
    url: 'https://api.myapp.com/contacts?needs_enrichment=true&limit=500',
    method: 'GET',
  }))

  // Process in batches of 50 to respect API rate limits
  .then(splitInBatches({ batchSize: 50 }))

  // Enrich each contact via Clearbit
  .then(httpRequest({
    url: 'https://person.clearbit.com/v2/people/find',
    method: 'GET',
    queryParameters: { email: '={{ $json.email }}' },
    headers: { Authorization: '={{ $env.CLEARBIT_KEY }}' },
    options: { batching: { batch: { batchSize: 10, batchInterval: 1000 } } },
  }))

  // Transform and save
  .then(code({
    language: 'typescript',
    code: `
      return items.map(item => ({
        json: {
          contactId: item.json.contactId,
          company: item.json.company?.name,
          title: item.json.title,
          linkedIn: item.json.linkedin?.handle,
          enrichedAt: new Date().toISOString(),
        }
      }))
    `,
  }))

  .then(httpRequest({
    url: 'https://api.myapp.com/contacts/bulk-update',
    method: 'PATCH',
    body: '={{ JSON.stringify($json) }}',
  }))

  .build()

Step 5: Convert Between JSON and TypeScript

// tools/convert.ts — Bidirectional workflow conversion
import {
  generateWorkflowCode,
  parseWorkflowCode,
  validateWorkflow,
} from '@n8n/workflow-sdk'

// JSON → TypeScript (import existing workflows as code)
const existingWorkflowJson = require('./exported-workflow.json')
const tsCode = generateWorkflowCode(existingWorkflowJson)
console.log(tsCode)
// Outputs clean TypeScript using WorkflowBuilder API

// TypeScript → JSON (deploy code-defined workflows)
const workflowJson = parseWorkflowCode(tsCode)
console.log(JSON.stringify(workflowJson, null, 2))
// Outputs valid n8n JSON ready for import

// Validate before deploying
const errors = validateWorkflow(workflowJson)
if (errors.length > 0) {
  console.error('Validation errors:', errors)
  process.exit(1)
}
console.log('Workflow is valid ✓')

Step 6: Deploy Workflows via n8n API

// deploy.ts — Push SDK-built workflows to n8n instance
import { WorkflowBuilder } from '@n8n/workflow-sdk'

async function deployWorkflow(workflow: ReturnType<WorkflowBuilder['build']>) {
  const response = await fetch(`${process.env.N8N_URL}/api/v1/workflows`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-N8N-API-KEY': process.env.N8N_API_KEY!,
    },
    body: JSON.stringify(workflow),
  })

  const result = await response.json()
  console.log(`Deployed: ${result.name} (ID: ${result.id})`)

  // Activate the workflow
  await fetch(`${process.env.N8N_URL}/api/v1/workflows/${result.id}/activate`, {
    method: 'PATCH',
    headers: { 'X-N8N-API-KEY': process.env.N8N_API_KEY! },
  })

  console.log(`Activated: ${result.name}`)
  return result.id
}

// Deploy all workflows from code
const workflows = [
  require('./workflows/data-sync'),
  require('./workflows/lead-routing'),
  require('./workflows/ai-support-agent'),
]

for (const wf of workflows) {
  await deployWorkflow(wf)
}

Guidelines

  • @n8n/workflow-sdk
    v0.2.0 is an early release (Feb 2026) — API may evolve. Pin the version.
  • Use
    generateWorkflowCode()
    to migrate existing JSON workflows to code — great for version control.
  • validateWorkflow()
    catches node configuration errors before deployment — use in CI.
  • n8n expressions (
    ={{ }}
    ) work in all string parameters — reference previous node data with
    $json
    ,
    $env
    ,
    $fromAi()
    .
  • AI/LangChain nodes use
    .withSub()
    to attach language models, memory, and tools to agent nodes.
  • The SDK outputs standard n8n JSON — deploy via the n8n REST API or import through the UI.
  • License is Sustainable Use (n8n proprietary), not open source — check terms for your use case.
  • For workflow-as-code patterns: keep workflows in a
    workflows/
    directory, validate in CI, deploy with a script.