> your AI agent picks dependencies from memory; give it dated facts — try starlog.dev ↗ vet your agent's deps ↗ vibe-coding is fine. vibe-importing isn’t. — try starlog.dev ↗ vibe-importing isn’t fine ↗ your agent has never seen your private packages — try starlog.dev ↗ facts for private packages ↗ a linter for the dependencies your AI agent picks — try starlog.dev ↗ a linter for agent deps ↗

Back to Articles

n8n: Building Self-Hosted Workflow Automation That Doesn't Lock You In

[ View on GitHub ]

n8n: Building Self-Hosted Workflow Automation That Doesn't Lock You In

Hook

While Zapier processes over 6 billion tasks monthly, n8n quietly powers automation for teams who'd rather trust their infrastructure than a third-party SaaS—and its 187K GitHub stars suggest they're onto something.

Context

Workflow automation platforms have traditionally forced a binary choice: accept the simplicity and vendor lock-in of cloud services like Zapier and Integromat, or build everything from scratch with task queues and custom code. The former works until you hit rate limits, need data sovereignty, or want to automate something involving sensitive information that compliance won't let you send to a third party. The latter gives you control but means reinventing the wheel for every API integration, building your own execution engine, and maintaining infrastructure that doesn't directly differentiate your product.

n8n emerged in 2019 to challenge this false dichotomy. Built by Jan Oberhauser after years of frustration with existing automation tools, it combines the visual workflow builder that makes automation accessible with the ability to drop into code when you need it. More importantly, it's self-hostable with a fair-code license—source available with generous usage rights, but with restrictions preventing competitors from simply reselling it as a service. This licensing model has enabled n8n to build a sustainable business while giving developers the sovereignty they need for production systems handling sensitive data or requiring air-gapped deployments.

Technical Insight

At its core, n8n implements workflows as directed acyclic graphs (DAGs) where each node represents an operation—an API call, a transformation, a conditional branch, or custom code execution. What makes the architecture compelling is how it balances abstraction with escape hatches. Each node type is implemented as a TypeScript class extending base node interfaces, making it straightforward to contribute new integrations or build proprietary ones internally.

Here's a simplified example of how n8n executes a workflow combining a webhook trigger, data transformation, and an API call:

// Webhook trigger receives data
{
  "nodes": [
    {
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [250, 300],
      "webhookId": "abc123",
      "parameters": {
        "path": "customer-created",
        "responseMode": "onReceived"
      }
    },
    {
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [450, 300],
      "parameters": {
        "jsCode": "return items.map(item => ({\n  json: {\n    email: item.json.email.toLowerCase(),\n    name: `${item.json.firstName} ${item.json.lastName}`,\n    timestamp: Date.now()\n  }\n}));"
      }
    },
    {
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [650, 300],
      "parameters": {
        "method": "POST",
        "url": "https://api.internal.com/users",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "httpBasicAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json }}"
      }
    }
  ],
  "connections": {
    "Webhook": { "main": [[{ "node": "Code", "type": "main", "index": 0 }]] },
    "Code": { "main": [[{ "node": "HTTP Request", "type": "main", "index": 0 }]] }
  }
}

This JSON structure represents how n8n persists workflows. The execution engine reads this configuration and processes items through the graph, with each node receiving an array of items and outputting transformed items to connected nodes. The Code node demonstrates n8n's philosophy: you can use pre-built nodes for 90% of tasks, but when you need custom logic, you write actual JavaScript that operates on the data stream.

The execution architecture is particularly well-thought-out for production use. n8n supports three execution modes: main process (development), separate process (isolation), and queue mode (scalability). In queue mode, workflow executions are pushed to a Redis-backed Bull queue, allowing you to scale worker processes horizontally. This means a single n8n instance can handle thousands of concurrent workflows without blocking the API server that manages the editor and webhook endpoints.

For AI capabilities, n8n has deeply integrated LangChain, providing nodes for LLM calls, vector stores, agents, and chains. Rather than treating AI as a separate feature, they've made it first-class in the workflow graph. You can build an AI agent that queries a vector database, calls tools implemented as sub-workflows, and maintains conversation memory—all visually, with the option to drop into code for custom tool implementations:

// Custom AI tool implemented in a Code node
const tools = [
  {
    name: 'lookup_customer',
    description: 'Looks up customer information by email',
    schema: {
      type: 'object',
      properties: {
        email: { type: 'string', description: 'Customer email address' }
      },
      required: ['email']
    },
    func: async ({ email }) => {
      const response = await $http.get(
        `https://api.internal.com/customers?email=${email}`
      );
      return JSON.stringify(response.data);
    }
  }
];

return [{ json: { tools } }];

The credential system deserves mention for its pragmatism. Rather than forcing every secret through environment variables or external vaults (though those are supported), n8n encrypts credentials in its database using a master encryption key. This makes it trivial to share workflows with embedded, encrypted credentials across team members, while still supporting integration with external secret managers for enterprise deployments.

One architectural choice that sets n8n apart is its expression system. Using {{ }} syntax, you can reference data from previous nodes, transform it inline with JavaScript, and even use moment.js or lodash functions without importing anything. It's not trying to create a new DSL—it's just JavaScript with convenient shortcuts for common workflow patterns.

Gotcha

The fair-code license is both n8n's strength and its primary gotcha. The Sustainable Use License grants broad rights for internal use, modification, and even distribution, but prohibits offering n8n as a service to third parties or using it to build a competing product. If you're building an internal automation platform for your organization, you're fine. If you're a consultancy wanting to offer "automation as a service" powered by n8n, or building a product that competes with n8n's core offering, you need an enterprise license. This isn't necessarily bad—it's what funds development—but it's a consideration that teams must evaluate upfront.

Performance can become a concern at scale. Being Node.js-based, n8n handles I/O-bound workflows excellently (API orchestration, webhooks, database operations), but CPU-intensive transformations on large datasets can struggle. A workflow processing thousands of JSON objects through complex transformations will be slower than a compiled Go or Rust service. The workaround is splitting heavy computation into separate services that n8n orchestrates, but this adds architectural complexity. Additionally, while queue mode enables horizontal scaling of execution workers, the main process (handling the editor, API, and workflow management) doesn't scale horizontally without additional load balancing complexity.

The learning curve is steeper than advertised. While simple workflows are genuinely no-code friendly, the moment you need error handling, data transformation beyond basic mapping, or conditional logic, you're writing JavaScript expressions. The documentation assumes familiarity with async programming, HTTP semantics, and data structures. Teams expecting a truly no-code experience may find themselves needing JavaScript knowledge sooner than anticipated. This isn't necessarily a limitation—it's an honest reflection of what workflow automation at scale requires—but it's worth setting expectations accordingly.

Verdict

Use if: You need workflow automation with data sovereignty, are building internal tooling where you want infrastructure control, have technical team members comfortable with JavaScript, require AI-powered workflows with custom data sources, or need air-gapped deployments for compliance. n8n is ideal for DevOps teams automating infrastructure, data engineers building ETL pipelines without Airflow's complexity, or SaaS companies needing customer-specific automation workflows they host themselves. Skip if: You're looking for a purely visual no-code tool for non-technical users (Zapier is simpler), need a purely open-source license without restrictions (consider Apache Airflow for data workflows), plan to build a competing automation service without an enterprise agreement, or have extremely high-throughput requirements better served by compiled languages (consider Temporal for mission-critical workflows). For teams already comfortable with TypeScript and Node.js, n8n hits the sweet spot of flexibility, self-hosting, and developer experience that proprietary automation platforms can't match.