Zapier gets expensive fast. Their Professional plan starts at $100 a month for just 2,000 tasks, and if you're running 50,000, you're easily burning $500 or more every month. Meanwhile, you can spin up n8n, Windmill, or Activepieces on a $10/month Hetzner VPS and get essentially unlimited runs, zero per-task billing, and complete ownership of your data.
The real debate isn't whether self-hosting saves you cash - it obviously does. It’s figuring out which engine actually makes sense for how you work.
- n8n is the runaway favorite with over 400 integrations, though its Fair Code license comes with commercial strings attached 2. Windmill is hands-down the speed demon (roughly 10x faster than Airflow), built specifically for devs who'd rather write code than drag boxes around 3. Activepieces goes full MIT open-source and brings native Model Context Protocol (MCP) support right into AI agent setups
While all three tackle automation, they approach it from totally different angles. Let's walk through what actually matters when you're deciding between them.
Why Self-Host Your Workflow Automation?
To put the price gap into perspective, look at how the monthly bill scales across platforms:
| Monthly tasks | Zapier (Professional) | Make (Pro) | Self-hosted (Hetzner CX22) |
|---|---|---|---|
| 2,000 | $100 | $18 | ~$10 |
| 10,000 | $250 | $55 | ~$10 |
| 50,000 | $500+ | $165+ | ~$10 |
| Unlimited | Not available | Not available | ~$10 |
That VPS price tag stays at ten bucks whether you run ten workflows or ten million. Beyond the obvious wallet relief, there are huge practical perks to running your own box:
Data privacy: Customer records and credentials never leave your servers, saving you massive compliance headaches.
Zero vendor lock-in: You aren't at the mercy of sudden pricing changes or sunsetted tiers; your logic runs on your own iron.
Full control: Need a weird tweak? Fork the repo, patch the code, and keep moving.
Snappy latency: Internal automations run right next to your databases without bouncing through third-party cloud regions.
Naturally, the catch is maintenance. You're the one managing updates, scheduling backups, and keeping the lights on.
If your team already lives in Docker or Kubernetes, it's barely a blip on your radar. If you don't have anyone comfortable in a terminal, it’s a genuine operational trade-off you need to weigh.
n8n: The Visual Automation Workhorse
n8n is basically the undisputed heavyweight of self-hosted automation, boasting over 68,000 GitHub stars. It gives you a sleek node-based canvas where you can wire complex services together without touching code, though you can drop in custom JavaScript or Python blocks whenever you hit a wall.
Where n8n Excels
Its library of pre-built integrations is by far its biggest selling point. You get over 400 built-in nodes out of the box, handling everything from Slack and Gmail to raw Postgres queries and arbitrary webhooks. Plus, the community is massive, so if you're trying to build something common, someone has likely shared a workflow template for it already.
They've also done a fantastic job integrating modern AI. n8n natively handles LangChain agents, structured tool calling, and vector databases, which means you can assemble a functional RAG pipeline or an autonomous research bot right on the visual canvas.
Where n8n Falls Short
Memory hunger is the number one gripe you'll hear from people running it themselves. n8n sits around 300 to 500 MB of RAM just idling, and it easily spikes between 1 and 2 GB when a heavy workflow kicks off. Once you toss in PostgreSQL (which you really should use for production), you'll want at least 1.75 to 2.75 GB of headroom on your server just to feel comfortable.
Its license is another common pain point. n8n operates under a "Fair Code" model (their Sustainable Use License), not pure open source. It’s completely free for internal company use, but you aren't allowed to turn around and sell it as a managed service to third parties. That won't bother most in-house teams, but if you're an agency building client-facing SaaS products, it's an immediate blocker.
Self-Hosting n8n
Spinning up a quick sandbox instance takes about two minutes using Docker:
Bash
docker run -it --rm \
--name n8n \
-p 5678:5678 \
-v n8n_data:/home/node/.n8n \
n8nio/n8nIf you're putting this into production, skip the default SQLite setup and spin up Docker Compose with Postgres:
YAML
services:
n8n:
image: n8nio/n8n
ports:
- "5678:5678"
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=changeme
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
deploy:
resources:
limits:
memory: 4G
reservations:
memory: 2G
postgres:
image: postgres:16
environment:
- POSTGRES_DB=n8n
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=changeme
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
n8n_data:
postgres_data:Give the container at least 4 GB of RAM if you plan on crunching heavy payloads. SQLite is fine for a quick weekend test, but under heavy concurrent traffic, it loves to lock up and corrupt data.
Common n8n Self-Hosting Gotchas
Webhooks breaking behind your proxy. Make sure you set the WEBHOOK_URL environment variable to your actual external domain instead of localhost. If you forget this, n8n registers internal network addresses that outside webhooks can't talk to.
Missing run history after a restart. If you use SQLite without properly mapping a persistent host volume, your database gets wiped every time the container cycles. Always make sure /home/node/.n8n points to persistent storage.
RAM spikes choking the machine on big payloads. n8n pulls raw datasets directly into memory as they pass from one node to the next. If an upstream query pulls 100,000 database rows all at once, your server will choke; paginate those queries or offload the heavy lifting to an external script via the Execute Command node.
The most common trap is trying to cram n8n onto a tiny 2 GB VPS alongside other services. A simple alert triggers a database sync, which fires a downstream webhook, and suddenly three flows run in parallel.
The container runs out of memory, Docker quietly kills it, and your active executions vanish. Give it a clean 4 GB instance or enforce strict resource limits in your orchestrator so it doesn't bring the whole server down.
Windmill: The Developer-First Speed Machine
Windmill is built for engineers who roll their eyes at visual node editors. Instead of wrestling with drag-and-drop boxes, you write clean scripts in Python, TypeScript, Go, Bash, or SQL, letting Windmill handle scheduling, execution queues, auto-retries, and front-end generation.
Where Windmill Excels
Pure execution speed is where Windmill completely laps the competition. Rather than spinning up a brand-new container for every task, it uses persistent, lightweight runtimes that strip out the startup latency that makes engines like Airflow feel sluggish.
The benchmark numbers are genuinely wild:
Python cold start: roughly 60ms
Deno/Bun cold start: roughly 30ms
JavaScript evaluation: ~8ms per expression
Worker throughput: up to 1,000 steps every second on dedicated nodes
Raw performance: easily 10x faster than Apache Airflow across standard pipeline benchmarks
Another neat trick is automatic UI generation. As soon as you type-hint your script parameters, Windmill generates an interactive web form for it. That means your engineers can write clean code while ops or support staff get a friendly dashboard to trigger runs without touching the terminal.
Where Windmill Falls Short
It is definitely not a no-code playground. There’s no simple canvas for dragging two apps together; everything fundamentally revolves around code. If your marketing or operations folks expect to build their own integrations without writing a script, Windmill will frustrate them quickly.
The library of pre-packaged connectors is also noticeably leaner. Windmill expects you to write quick API calls or adapt community scripts rather than clicking a pre-built app card, so you'll end up writing a bit more boilerplate code for everyday services.
Its built-in AI tooling is also more bare-bones. You can easily ping LLMs via Python or TypeScript scripts, but you won't find a visual flow builder for autonomous agents or out-of-the-box MCP server tooling here.
Self-Hosting Windmill
Getting a basic Windmill setup running via Docker Compose is remarkably painless:
Bash
curl https://raw.githubusercontent.com/windmill-labs/windmill/main/docker-compose.yml -o docker-compose.yml
docker compose up -dThe stack bundles PostgreSQL and exposes the UI on port 8000. It runs much lighter than n8n when idle, usually sipping just 150 to 300 MB of RAM for the base service.
Scaling it in production is simply a matter of adding worker containers to the pool. Each worker independently pulls tasks from the central queue, making it trivial to isolate mission-critical workloads on dedicated hardware.
Common Windmill Self-Hosting Gotchas
Workers sitting idle and ignoring jobs. Double-check that your worker containers can actually talk to the central Postgres database. A typo in the DATABASE_URL string inside the worker environment is almost always the culprit.
Python library build errors. Windmill caches pip packages per version combo. If a library needs OS-level C headers (like compiling psycopg2 against libpq-dev), you'll need to bake those dependencies into a custom base worker image.
TypeScript tasks randomly cutting out. Windmill sets a default script execution timeout of 900 seconds. If you're running long backfills or massive scraping jobs, bump up that limit in the script settings or adjust the TIMEOUT_WAIT_RESULT environment variable.
Activepieces: AI-Native and Fully Open Source
Activepieces is the newest platform of the bunch, and it targets the intersection of automation and modern AI workflows. Unlike n8n's more restrictive licensing, Activepieces is published under a standard MIT license, making it completely open and friction-free for commercial use.
Where Activepieces Excels
Native Model Context Protocol (MCP) support is where Activepieces shines. It can automatically expose its 400+ built-in app pieces as MCP tools. That means an AI agent living in Claude Desktop or Cursor can natively talk to Gmail, HubSpot, or Stripe right through your self-hosted Activepieces instance without extra middleware.
Even better, you can bundle entire multi-step automations into an individual MCP endpoint. You can build a flow that checks your warehouse inventory, cuts an invoice, and alerts a Slack channel, then let your LLM call that entire sequence as a single tool.
The user experience is clean and intuitive, earning a 9.1 ease-of-setup score on G2 compared to n8n's 7.7. The builder feels like a lightweight, modern web app rather than an overwhelming industrial dashboard, which makes non-technical teammates feel right at home.
Where Activepieces Falls Short
Because it's relatively young, the ecosystem hasn't reached the maturity of n8n or Windmill yet. You'll find fewer ready-made templates, community threads are sparser when you hit obscure bugs, and enterprise battle-testing is still accumulating. There are also frequent community discussions regarding sluggish execution speeds compared to n8n when pushing high transaction volumes.
Its library of roughly 280+ pieces is also still playing catch-up to n8n's massive catalog. The everyday staples are well covered, but if you rely on obscure SaaS apps, you might have to build your own piece from scratch.
Self-Hosting Activepieces
Activepieces is just as quick to spin up with Docker Compose:
Bash
git clone https://github.com/activepieces/activepieces.git
cd activepieces
cp .env.example .env
docker compose up -dThe stack uses Postgres and Redis under the hood. Expect it to use about 300 to 500 MB of RAM under normal daily operations, putting it roughly on par with n8n.
Common Activepieces Self-Hosting Gotchas
Pieces failing to load after pulling updates. Clear your local pieces cache and cycle the container. If the core server version gets out of sync with downloaded piece packages, you'll see silent load errors.
Broken OAuth callbacks after changing your domain. Activepieces saves the redirect URI when you first authenticate an app. If you change your public domain later, you'll need to re-authenticate those integrations so the callback matches.
Memory spikes during AI processing. Passing large PDFs or uncompressed image files through AI nodes can make container RAM spike aggressively. Keep an eye on docker stats and make sure your containers have explicit memory caps configured.
Head-to-Head Comparison
| Feature | n8n | Windmill | Activepieces |
|---|---|---|---|
| License | Fair Code (Sustainable Use) | AGPLv3 / Commercial | MIT |
| Primary interface | Visual node canvas | Code editor + auto UI | Linear step builder |
| Built-in integrations | 400+ | ~100 (+ custom scripts) | 280+ |
| AI agent support | LangChain nodes, tool calling | Script-based LLM calls | Native MCP, AI SDK |
| MCP support | No | No | Yes (400+ MCP tools) |
| Cold start (per step) | ~50-100ms | ~30-60ms | ~50-100ms |
| Idle RAM | 300-500 MB | 150-300 MB | 300-500 MB |
| Best for | Blended teams of devs and non-engineers | Devs who live in raw code | AI agent pipelines & MCP setups |
| Self-host difficulty | Easy (Docker) | Easy (Docker) | Easy (Docker) |
| GitHub stars | 68k+ | 15k+ | 12k+ |
Which One Should You Pick?
Go with n8n if you want the deepest integration catalog and need an interface that both technical and non-technical teammates can comfortably use. The canvas is polished, the community is everywhere, and you rarely have to build common flows from scratch. Just make sure to give it enough RAM and double-check that its Fair Code license works with your business model.
Go with Windmill if you have an engineering team that prioritizes raw execution speed and clean version-controlled code. Being able to run thousands of steps per second with practically zero cold-start delay makes it a no-brainer for heavy data pipelines and backend tasks. The trade-off is that non-programmers won't be building their own flows here.
Go with Activepieces if your primary goal is wiring up AI agents and LLM tool calling. The native MCP implementation, clean step-by-step UI, and permissive MIT license make it uniquely suited for AI-heavy workflows. Just keep an eye on execution performance as your scale climbs, and expect to write the occasional custom piece for niche tools.
All three run smoothly via standard Docker Compose, and each works fine with alternative OCI runtimes like Podman or nerdctl if you avoid Docker Desktop's enterprise licensing.
If you already have n8n handling automations like AI image generation, there's no reason to rip everything apart. A lot of engineering teams pair them up: keeping n8n for quick third-party app wiring, while dropping in Windmill for heavy data processing or Activepieces for AI agent tool calls. Choose the engine that fits the specific workload, not whichever one happens to be trending.
