Self-hosted service
windmill-labs/windmill avatar
windmill-labs/windmill

Windmill: scripts, flows and internal UIs on one self-hostable engine

Open-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.

18,071 stars1,106 forksRustNOASSERTION

At a glance

What is it?
Windmill turns Python, TypeScript, Go or Bash scripts into webhooks, workflows and autogenerated UIs. It is aimed at teams that want a self-hostable alternative to Retool and a simplified Temporal, and the trade-off is a Postgres-centric deployment you have to run yourself.
Who is it for?
Adopt Windmill if you already run Postgres and want scripts in several languages to become webhooks, schedules and internal UIs without building a frontend for each one. Skip it if you need a plain cron replacement with no database, or if AGPLv3 licensing is a blocker for your distribution model.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Windmill solves for teams with too many one-off scripts

Most internal automation starts as a script in a repository, gets a cron entry, and then needs a way for a non-author to trigger it. The README frames Windmill as a developer platform for internal code: APIs, background jobs, workflows and UIs. The unit of work is a script in Python, TypeScript, Go, Bash, SQL, GraphQL, PowerShell or Rust, and the platform derives the interface from the script's parameters rather than asking you to write one.

The intended audience is a team that already writes code and wants to stop rebuilding the same wrapper around each task. A script's parameters are parsed and used to generate a frontend, per the README, so a function signature becomes a form. That is the part that separates Windmill from a job runner: the same artifact can be called from a schedule, a webhook, an HTTP route, a Kafka topic, a WebSocket or an email trigger, according to the trigger list in the README.

The script-to-UI mechanism and how flows compose it

The README's TypeScript example shows the shape of a Windmill script. Dependencies are imported directly, including versioned npm packages such as [email protected], and the exported main function takes typed arguments. A Postgresql type in the example is a plain object type, and the comment notes that a +Resource type gives a type-safe reference to a resource instead. Variables are fetched by path at runtime through the wmill client, for example wmill.getVariable("f/company-folder/my_secret"), and state is kept per script with wmill.getState() and wmill.setState(). Logs are printed with console.log and the return value is serialized as JSON.

That is the data flow: the parameter list defines the input contract, resources and variables resolve secrets and connections by path, and the return value is the output. Flows chain scripts together, and the README points at WindmillHub for scripts shared by the community. Apps are a further layer built on top of scripts and flows for richer interfaces. The same script therefore serves as an API endpoint, a step in a flow, and the backend of an app, which is the argument for putting them in one system rather than three.

Self-hosting Windmill with Docker Compose

The repository ships a docker-compose.yml at the top level, and the README lists Docker Compose, Kubernetes via Helm charts, and cloud providers as self-hosting routes. The compose file defines a db service using postgres:18 with POSTGRES_PASSWORD set to changeme, POSTGRES_DB set to windmill, and an internal expose of 5432, plus a healthcheck running pg_isready -U postgres. The windmill_server service is defined alongside it. To point Windmill at an external database instead, the comment in the compose file says to set the db service replicas to 0 and set DATABASE_URL to the external database url in the .env file.

The compose file carries a long warning about upgrading Postgres. From version 18 the official image keeps the cluster in a major-version subdirectory, so the volume mount has to be the parent directory /var/lib/postgresql rather than the pre-18 data path. The comment states that mounting the old path makes the image exit rather than start, which turns a stale cluster into a visible failure instead of an empty instance. It also warns that migrating from Postgres 16 means dumping the whole cluster with pg_dumpall, not just the windmill database, because Windmill keeps datatable, DuckLake and wm_fork_* databases beside it and grants its RLS policies to cluster-level roles. A single-database dump loses both silently, according to that comment.

For Kubernetes, the README points to Helm charts rather than inlining a manifest, so there is no chart snippet to copy here. The README also notes that OAuth, SSO and SMTP are configured separately, and that Windmill Labs offers dedicated instances and commercial support alongside the AGPLv3 code.

Running a script locally with the wmill client

The README states that you can run scripts locally by passing the right environment variables for the wmill client library to fetch resources and variables from your instance. The Python client is published on PyPI as wmill, which is what the badge in the README links to.

Install the client and run a script against your instance:

bash
pip install wmill

The README does not list the individual environment variable names for local execution; it only says they are needed for the wmill client to reach your instance. Check the CLI documentation linked from the README before assuming a name.

For editing with full IDE support rather than a terminal, the README lists a CLI, a VS Code extension that also works in Cursor, Git Sync for two-way synchronization with a Git repository, and Claude Code for AI-assisted development of scripts, flows and apps. The extension and Git Sync are the two paths intended for teams that want their scripts to live in version control rather than only in the web IDE.

Where Windmill is the wrong tool

Windmill is not a drop-in cron replacement. It requires a Postgres database, and the compose file's upgrade notes show how much of the system sits on that database: separate databases for datatable, DuckLake and forked runs, plus RLS policies granted to cluster-level roles. If your workload is a handful of shell commands on a single host, that database is a cost with no matching benefit.

The Postgres 18 change is a concrete operational hazard. A deployment that mounts the pre-18 data path will not start, and the compose comment is explicit that recovering from a 16 cluster requires a full pg_dumpall rather than a single-database dump. Teams that treat their workflow database as disposable will discover it is not. The compose file also ships POSTGRES_PASSWORD: changeme, which is a default to replace before anything is reachable.

On the licensing side, the README states Windmill is fully open-sourced under AGPLv3, and the repository contains LICENSE-AGPL alongside LICENSE-APACHE and a CLA.md. The GitHub API reports the license as NOASSERTION, so the repository metadata does not resolve to a single identifier even though the README and the LICENSE-AGPL file both point at AGPLv3. If your distribution model is sensitive to copyleft, read the licence files rather than the badge. Nothing here is legal advice.

How Windmill differs from Temporal and Airflow

The README positions Windmill as a simplified Temporal with autogenerated UIs and custom UIs, and the description calls it an open-source alternative to Retool and Temporal. The difference in approach is where the interface comes from. Temporal gives you durable execution and expects you to build the operations surface yourself; Windmill derives a form from the script's parameters and lets you assemble apps on top, so the UI is a product of the script rather than a separate project.

Against Airflow the README's own claim is speed, describing Windmill as the fastest self-hostable workflow engine and citing 13x versus Airflow. That figure comes from the project's own material and is not something this article can verify. The more useful structural difference is the execution model: Airflow schedules tasks defined in Python DAGs, while Windmill executes scripts in any of the supported languages as individually addressable units that can also be triggered by HTTP, Kafka or a webhook. If your pipelines are already expressed as DAGs and your team knows Airflow, the migration cost is real and the speed claim alone does not settle it.

Editorial conclusion

Adopt Windmill if you already run Postgres and want scripts in several languages to become webhooks, schedules and internal UIs without building a frontend for each one. Skip it if you need a plain cron replacement with no database, or if AGPLv3 licensing is a blocker for your distribution model. Before committing, verify three things against your own instance: that the Python client wmill is available for your version, that the docker-compose.yml db service and the DATABASE_URL setting match the Postgres you intend to run, and that the environment variables your deployment needs are documented for the release you pin.

Frequently asked questions

How do I install Windmill on my own server?

The README lists Docker Compose, Kubernetes with Helm charts, and cloud providers as self-hosting options, and the repository includes a docker-compose.yml with a postgres:18 db service and a windmill_server service. To use an external database instead, the compose file says to set the db service replicas to 0 and set DATABASE_URL in the .env file.

Which programming languages can Windmill scripts be written in?

The README lists Python, TypeScript, Go, Bash, SQL, GraphQL, PowerShell, Rust and more. The example script in the README is TypeScript and imports npm packages directly, including a versioned dependency.

What can trigger a Windmill script or flow?

The README lists schedules, webhooks, HTTP routes, Kafka, WebSockets, emails and more as triggers for scripts and flows.

Can I run Windmill scripts locally during development?

Yes. The README says you can run scripts locally by passing the right environment variables for the wmill client library to fetch resources and variables from your instance, and the Python client is published on PyPI as wmill. The README does not list the individual variable names.

What licence does Windmill use?

The README states Windmill is fully open-sourced under AGPLv3 and the repository contains a LICENSE-AGPL file. The GitHub API reports the licence as NOASSERTION, so check the licence files directly for your own distribution model.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. windmill-labs/windmill on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/windmill-labs-windmill.svg)](https://hysenlabs.com/projects/windmill-labs-windmill)