How Magic Omniverse adopts Windmill as the orchestration spine of a multi-tenant commerce platform — what we build on it, why it scales, and what falls away.
After scoring it head-to-head against Inngest across 19 dimensions weighted to our actual platform needs, Windmill won — narrowly, deliberately, and for reasons specific to where we are.
It is the only one of the candidates that can replace N8N end-to-end while also giving us code-driven workflows, internal admin tools, native cron and webhooks, and full polyglot scripting — all in one self-hosted, version-controlled platform.
One tool, one mental model, one place to look when something runs or fails. That consolidation is the prize.
A multi-tenant headless commerce platform across two boxes — DEV and NETCUP — running thirteen Medusa-powered storefronts, an AI agent layer on Mastra, and a constellation of integrations glued together by N8N.
The good: each tenant has its own Medusa instance, its own Postgres database, its own Redis, its own search. Blast radius is small. Per-tenant work is isolated. Adding a new customer is technically possible.
The bad: integration logic lives in 29 N8N workflows that drift between DEV and NETCUP, are invisible to version control, and were never designed to scale beyond glue. AI agents have started accreting inside those same workflows — a parallel agent system fighting Mastra for ownership.
The opportunity: an ERP integration for a real customer is on deck. So is Amazon. So is the rest.
Picture N8N's job — running schedules, webhooks, integrations between systems — but written by engineers, version-controlled in your monorepo, with native support for any language, and a built-in way to ship internal admin UIs.
It is a single open-source binary, written in Rust for speed, that does five things very well:
TypeScript, Python, Go, Bash, SQL, PowerShell. Each script is a function — testable, reusable, version-controlled. Imagine a directory of small useful programs that anything can call.
Chain scripts together. Branch on conditions. Loop over arrays. Run steps in parallel. Retry on failure. Either as code, or as visual flows — same engine, two surfaces.
Drag-and-drop admin tools that read from databases, run scripts, and present data. Think "tenant onboarding panel" or "ERP sync status dashboard" — built in an afternoon, not a sprint.
Run anything on a schedule with full retry semantics, observability, and version history. Replaces every cron entry, every N8N schedule trigger, every "I'll write a script and add it to crontab" hack.
HTTP webhooks, Postgres changes, Kafka topics, NATS events, MQTT, S3 buckets, email. The platform reacts. Connectors are written, not configured-then-prayed-over.
Per-workspace secret storage, encrypted at rest, never logged. We pair it with Vaultwarden for org-level secrets — Windmill holds runtime keys, Vaultwarden holds long-term credentials.
Every entry below is something either already running on N8N, planned for the next two quarters, or a known platform gap. Windmill isn't a new project. It's the home for work that's already on the roadmap.
Order placed in Medusa → posted to ERP. Stock levels in ERP → reflected in Medusa. Master data flows both ways via custom APIs. Per-tenant config in Postgres so onboarding ERP customer #2 is a row insert, not a code change.
Listings synced from Medusa to Amazon SP-API. Inventory updated as orders flow. Marketplace orders pulled back into Medusa for unified fulfilment. Each marketplace is its own script module behind a shared adapter interface.
The eight existing supplier connectors — Spranz, Moxz, Langenberg, XD Connect, PF Concept, Mid Ocean, Toppoint, New Wave — move from N8N schedules and ad-hoc cron into Windmill flows. Same logic, observable, retryable, versioned.
Today: a manual checklist. Tomorrow: a Windmill flow that creates the database, runs migrations, provisions the Medusa instance, templates an Nginx vhost, requests a Let's Encrypt cert. End-to-end. Five minutes, fully reproducible.
Windmill workflows call Mastra agents in magic-mcp over HTTP or MCP. Agents reason, tools act, workflows orchestrate. Three layers, one direction of dependency. AI stops accreting inside N8N nodes.
Tenant management dashboard. Sync status board. Order replay panel. Customer support tools. Each one a Windmill App — a few hours each instead of a Next.js project. Auth gated by Zitadel/WorkOS.
Per-tenant database dumps to encrypted offsite storage. Filesystem snapshots of /mnt/data/pim_data. Retention policies enforced. Verified restorable monthly. All as scheduled flows with paged failure alerts.
Stripe events. Mollie callbacks. Supplier fulfilment notifications. ERP push events. Every external party gets a signed Windmill webhook URL. Routing, validation, replay all handled in one place.
Per-tenant Postgres → ClickHouse warehouse for the AI/MCP layer to read across tenants. CDC-style sync via scheduled flows. Powers magic-mcp's cross-tenant tools without breaking tenant isolation.
Order confirmations, shipping updates, dunning emails, ops alerts. Templated, retried, logged. Pluggable provider — start with self-hosted Postal, swap if needed without touching workflows.
Triggered by GitHub Actions or manually. Run database migrations across tenants, restart specific containers, roll forward or back, verify health checks. Deploys become reviewable artefacts, not artisanal SSH sessions.
Lead capture from contact forms. Quote generation. Customer-tier upgrades. Subscription renewals. Stripe Tax filings. Whatever moves a customer from one state to another runs through one observable spine.
Events flow upward. Decisions flow downward. Each layer does one job. Anything that doesn't fit cleanly into one of the four is the wrong shape.
State lives in databases. Domain logic lives in Medusa. Reasoning lives in Mastra. Orchestration lives in Windmill. Each layer can be swapped out independently because each layer talks to the one below through a clean interface.
A trigger fires in Windmill — a webhook, a schedule, an event. A flow runs. The flow may call a Mastra agent for reasoning. The agent uses MCP tools to read or write commerce state. The result propagates back up.
A platform decision is only good if it earns its keep across every role that touches it. Here is how Windmill pays each one back.
Code is no longer the bottleneck — external coordination is. With AI-augmented build velocity, implementation collapses; the timeline is now paced by ERP customer schemas, Amazon's approval queue, and customer cutover windows.
The ERP project is still the forcing function. Use it to install the new pattern alongside the old. Let N8N die naturally as work moves through Windmill anyway.
Add Windmill to the monorepo as a Docker service. Build the ERP integration on it as the first production flow. Don't migrate anything yet — prove the pattern with real stakes.
External gating: ERP customer's own pace on schema availability and credentials.
The shape exists. Marketplace integration, tenant onboarding automation, the most-painful N8N flows ported. ClickHouse warehouse stood up. Code is days, calendar is weeks — Amazon's approval queue sets the pace.
External gating: Amazon SP-API approval typically 2–4 weeks in their queue.
The platform is running on Windmill for new work. Time to migrate the things that drag silently — auth, observability, infra. None of it user-visible. All of it pays compound interest.
External gating: Zitadel cutover windows — every tenant must re-auth, soak time non-negotiable.
By now five or fewer N8N workflows remain — all non-critical. Final sweep, retire the four DEV instances, reclaim the resources. The platform speaks one language end-to-end.
External gating: tenant-by-tenant migration windows, scheduled around customer demand.
Eight reasons tied to our actual stack — not generic feature comparisons. Each one is a concrete pain Windmill removes or a capability N8N can't reach.
N8N stores workflows in its own database. Our own CLAUDE.md says "do NOT import/export between DEV and NETCUP" — that's the drift speaking. Windmill workflows live as TypeScript / Python files in the monorepo. Same file deploys to both servers via existing CI. The drift problem becomes architecturally impossible.
Thirteen Medusa tenants. In N8N: duplicate a workflow 13 times, or build hairy "for each tenant" branching that breaks every time you add one. In Windmill: one parameterised flow, scheduled with each tenant_id. Add tenant 14 = insert one row in your config table. No workflow change.
Your supplier connectors already exist as TS modules in magic_pim/src/modules/connectors/. N8N can't import them — you'd reimplement the logic in HTTP and Code nodes. Windmill imports them directly. One connector implementation, called from Medusa, agents, and workflows alike.
Bi-directional ERP sync without type safety silently loses orders months after the integration ships. N8N's HTTP nodes treat responses as any. Windmill flows share types with your Medusa code — a renamed ERP field breaks the build, not production.
Windmill's core is Rust — sub-100ms job startup, 1000+ concurrent jobs per worker. N8N is Node.js with per-node execution overhead, and the four instances on DEV are the workaround. 8 suppliers × 13 tenants = 104 sync jobs per cycle. Windmill finishes in minutes; N8N needs more boxes.
Today: agents accreting inside N8N nodes and Mastra agents in magic-mcp. Two parallel systems, two tool catalogs, two memories. Windmill flows call Mastra over HTTP / MCP — workflow orchestrates, agent reasons. Each layer one job. The split-brain ends.
You will need: a tenant management dashboard, an ERP sync status board, an order replay panel, a customer support tool. In N8N world each is its own Next.js mini-project — days of work each. In Windmill, each is an App: drag a table, point it at a Postgres query, ship it the same afternoon.
N8N's fair-code Sustainable Use License restricts commercial-as-a-service use. Windmill's AGPLv3 doesn't, as long as you self-host unmodified. If you ever expose flow editing to your tenants — "let customers configure their own integrations" — only one of these two licences allows it.
If the eight reasons above are the why, the table below is the what: a literal before-and-after of how the platform looks running on each.
No platform decision is free. These are the tradeoffs we know about, and how we plan to keep them from biting.
Windmill isn't the destination. It's the shape that lets us build the destination — multi-tenant commerce that scales by adding rows, not by adding heroics.