Every engineering team eventually builds the same things: a cron job that syncs data between systems, a script that rotates API keys, an admin panel that lets ops trigger a workflow without SSH access, a data pipeline that runs nightly and needs to be monitored. Each of these starts as a quick script and ends up as a maintenance burden — deployed somewhere nobody remembers, undocumented, and definitely not tested.

Windmill is the platform that consolidates all of it. Write a script in Python, TypeScript, Go, Bash, or SQL — Windmill turns it into an API endpoint, a scheduled job, a webhook handler, and an auto-generated UI that non-engineers can trigger safely. Chain scripts into visual workflows. Build internal apps on top of them. Keep everything in Git. That's the entire value proposition, and it's genuinely compelling.

What Windmill is

Windmill is an open-source developer platform and workflow engine for building, deploying, and monitoring internal automation and tooling at scale. It's written in Rust (backend) with a Svelte frontend and PostgreSQL as the only database dependency. AGPLv3 licensed, self-hostable, and benchmarked at 13x faster than Airflow for workflow execution.

The platform has three distinct layers that work together:

  • Scripts — single-file programs in Python, TypeScript, Go, Bash, SQL, Rust, GraphQL, PowerShell, and more. Each script gets an auto-generated form UI, an API endpoint, a webhook, and can be scheduled as a cron job — automatically, with no boilerplate.
  • Flows — visual workflow editor for chaining scripts into multi-step pipelines with branching, parallelism, retries, error handling, and human-in-the-loop approval steps.
  • Apps — low-code app builder for creating internal dashboards and tools that trigger workflows and scripts through custom UIs, with granular permissions so non-engineers can use them safely.

Windmill is a Y Combinator company used in production at organizations including Pave, Investing.com, and others running hundreds of scripts and flows in business-critical automations.

The license — AGPLv3 with commercial carve-outs

Windmill's core is AGPLv3 — one of the strongest copyleft licenses. The key implications:

  • Self-hosting for internal use: completely free, no license required
  • Using Windmill's APIs internally: completely free
  • Wrapping Windmill in your SaaS product to offer to customers: requires a commercial license from Windmill Labs, or your product must be AGPLv3

Enterprise features (SAML SSO, audit logs, distributed dependency cache backed by S3, global cache sync for large clusters) are available in the Enterprise Edition. For self-hosted internal use, the Community Edition covers everything most teams need: the full workflow engine, all script languages, flows, apps, secrets management, scheduling, webhooks, and Git sync.

Scripts — the foundation

The script is Windmill's atomic unit. Write a function with typed parameters, and Windmill handles everything else automatically. A Python script that takes a username and plan might look like:

# upgrade_user.py
# Requirements: psycopg2-binary

import psycopg2

def main(username: str, plan: str, notify: bool = True) -> dict:
    """Upgrade a user's plan in the database."""
    conn = psycopg2.connect(wmill.get_resource("u/admin/postgres_prod"))
    # ... query logic
    return {"upgraded": username, "plan": plan}

Windmill reads the type hints, generates a form with the right input types (text field for username, dropdown for plan, checkbox for notify), creates an API endpoint at /api/w/{workspace}/jobs/run/p/{path}, adds a webhook URL, and makes it schedulable as a cron job. The dependencies (psycopg2-binary) are installed and cached automatically — no Dockerfile, no requirements.txt to maintain separately, no deployment pipeline to set up.

Resources (database credentials, API keys, OAuth tokens) are stored encrypted in Windmill and injected into scripts via wmill.get_resource(). Scripts never contain credentials directly — they reference named resources that are managed centrally with granular access controls.

Flows — visual workflow orchestration

Flows chain scripts together into multi-step workflows using a visual editor. Each step is a script — from your workspace, from WindmillHub (the community script library), or written inline. The flow editor supports:

  • Branching — conditional logic that routes to different steps based on previous output
  • Parallelism — fan out to multiple steps running concurrently, then collect results
  • For-each loops — iterate over a list with each item processed as a separate job
  • Error handling — retry policies, error branches, and compensation steps
  • Human-in-the-loop — suspend the workflow and send an approval request via email, Slack, or a form; resume when approved
  • Input transforms — JavaScript expressions that transform the output of one step into the input of the next

Flows are version-controlled, testable at each step, and can be triggered the same ways as scripts: API, webhook, schedule, or app button.

Workflow-as-code — the newest capability

Launched in April 2026, workflow-as-code lets you define complex workflows entirely in TypeScript or Python using @workflow and @task annotations. This is the same model as Temporal or Inngest — durable execution, checkpointing, parallelism — but with zero additional infrastructure and standard language tooling:

// etl_pipeline.ts
import { task, workflow } from "windmill-client";

@workflow
export async function etlPipeline(source: string, dest: string) {
  const data = await task(extractData, { source });
  const transformed = await Promise.all(
    data.chunks.map(chunk => task(transformChunk, chunk))
  );
  await task(loadData, { records: transformed.flat(), dest });
  return { loaded: transformed.flat().length };
}

@task
async function extractData(source: string) { /* ... */ }

@task
async function transformChunk(chunk: object) { /* ... */ }

@task
async function loadData(records: object[], dest: string) { /* ... */ }

Each task() call runs as a separate Windmill job — logged, retryable, with its own timeline entry. Between tasks, the workflow fully suspends and releases its worker. A workflow sleeping for 24 hours consumes zero worker resources during the wait. A workflow with 100 parallel tasks doesn't hold 100 workers simultaneously. This is durable execution without the operational complexity of running Temporal.

Git sync and local development

Windmill keeps everything in Git. A synced workspace looks like:

f/
├── etl/
│   ├── stripe_to_postgres.flow.yaml
│   └── stripe_to_postgres/
│       ├── fetch_invoices.ts
│       └── transform.py
├── devops/
│   └── rotate_iam_keys.ts
├── apps/
│   └── billing_dashboard.app/
├── resources/
│   ├── postgres_prod.resource.yaml
│   └── slack_webhook.resource.yaml
└── schedules/
    └── stripe_sync.schedule.yaml

Scripts, flows, apps, resources, and schedules all live in version control. Pull requests for changes to automation. Diffs that show exactly what changed. Rollback by reverting a commit. The wmill sync push command deploys changes from your local machine or CI/CD pipeline. Windmill also has a VS Code extension for local development with IDE features (autocomplete, type checking) and preview against your remote instance.

Triggers

Scripts and flows can be triggered by:

  • Schedule — cron expressions, with monitoring and alerting on failure
  • Webhook — unique URL per script/flow, supports sync and async execution
  • HTTP routes — custom REST API routes your scripts serve
  • Kafka / WebSocket / Email — event-driven triggers for reactive workflows
  • Slack command — trigger flows directly from Slack
  • App button — UI buttons in Windmill apps
  • CLIwmill run for local execution

Self-hosting Windmill

Docker Compose is the standard path. The stack is lean compared to most platforms — Windmill server, workers, and PostgreSQL:

# Clone the docker-compose setup
git clone https://github.com/windmill-labs/windmill
cd windmill

# Configure your .env (set WM_BASE_URL, SECRET_KEY, etc.)
cp .env.example .env

# Start
docker compose up -d

The default setup runs the server (stateless API), workers (pull jobs from the Postgres queue), and PostgreSQL. Add more workers by scaling the worker service horizontally — Windmill's architecture is stateless API + worker pool + Postgres queue, so horizontal scaling is straightforward.

Minimum viable server: 2 CPU cores and 2GB RAM for small workloads. Production with parallel workflows and many concurrent jobs benefits from more worker replicas and a dedicated database. A Helm chart is available for Kubernetes deployments.

Windmill vs the alternatives

vs n8n — n8n is a visual automation platform focused on connecting SaaS APIs with no-code blocks. Windmill is code-first — you write real programs and the platform handles the infrastructure. n8n is better for non-technical users and API integration workflows. Windmill is better for engineering teams who want real code, version control, and production-grade orchestration. They serve different primary audiences.

vs Airflow — Airflow is the incumbent for data pipeline orchestration, Python-based, DAG-driven. Windmill benchmarks at 13x faster for task execution, supports more languages, and has a significantly better developer experience (no Airflow DAG boilerplate, no Celery to manage, no separate webserver/scheduler/worker architecture). For new projects, Windmill is the better choice for most data pipeline use cases. For organizations already deep in Airflow, the migration cost matters.

vs Temporal — Temporal is the gold standard for durable workflow execution at scale — used at Stripe, Netflix, and others. It's also complex to operate: separate server, history service, matching service, and frontend service, plus SDK boilerplate. Windmill's workflow-as-code feature covers the core Temporal use case (durable execution, checkpointing, parallelism) with much lower operational complexity. For most teams, Windmill is sufficient. For Temporal-scale requirements (millions of concurrent workflows), Temporal's maturity is worth the operational cost.

vs Retool — Retool is a proprietary internal tools platform. Windmill's App builder covers the same use case — internal dashboards, admin panels, ops tools — with the code-first advantage that scripts underlying the UI are reusable in workflows, and everything is in Git. Retool wins on UI polish; Windmill wins on data sovereignty, cost, and code ownership.

vs Prefect / Dagster — these are Python-first data orchestration platforms with strong data engineering ecosystems. Windmill covers data pipeline use cases but is more general-purpose. For teams primarily building data pipelines with Python, Prefect or Dagster's richer data-specific features (lineage, asset management, data catalog) may be worth the specialization. For teams building a mix of data pipelines, internal tools, and automation, Windmill's unified platform avoids running multiple systems.

Who it's for

Good fit:

  • Engineering teams with a shelf of scripts and cron jobs they want to consolidate into one observable, version-controlled platform
  • Teams that want to give non-engineers safe access to trigger engineering workflows without SSH access
  • Organizations building data pipelines, ETL jobs, and automation that want production-grade orchestration without Airflow's complexity
  • Teams replacing Retool or Airplane with an open source, self-hostable alternative
  • DevOps teams who want to automate infrastructure operations with a developer-friendly platform

Not the right fit:

  • Non-technical users who want pure no-code automation — n8n or Make are simpler
  • Teams that need deep data catalog, lineage, and asset management — Dagster or Prefect are more specialized
  • Organizations building consumer-facing products — Windmill is for internal tooling

My take

Windmill solves the "script graveyard" problem — the accumulation of undocumented scripts, cron jobs running on forgotten servers, and ad-hoc automations that only the person who wrote them can operate. By turning scripts into first-class, observable, version-controlled, triggerable artifacts with auto-generated UIs, Windmill makes the gap between "someone wrote a script" and "anyone on the team can run this safely" disappear.

The workflow-as-code feature is the most interesting recent development. Getting Temporal-style durable execution without running Temporal's infrastructure is a meaningful practical improvement for teams that need it. The two-annotation model — @workflow and @task on regular TypeScript or Python functions — is elegant and the zero-worker-consumption-during-wait architecture is correct.

For DevOps teams specifically, Windmill is the platform I'd use to consolidate infrastructure automation: key rotation scripts, database maintenance jobs, deployment triggers, incident response runbooks that need a UI. The resource management (credentials stored centrally, referenced by name) and the approval workflow (suspend until a human approves, zero resources consumed while waiting) are exactly the right primitives for operational tooling.

The AGPLv3 license means you run it internally for free forever. Self-hosting on the same server running your other tools — Gitea, Traefik, Outline, Plane — adds negligible overhead for the capabilities it delivers.


PIPOLINE · DEVOPS CONSULTING

Need help setting up Windmill?

Getting Windmill into production — Docker Compose, worker scaling, Git sync configuration, resource setup for your databases and APIs, Traefik for HTTPS, and migrating your existing scripts and cron jobs into Windmill workflows — takes an afternoon to do properly. I can handle the full setup and build your first few workflows so your team sees the value immediately.

Get in touch at pipoline.com →