Windmill Labs
Windmill

The Pipedream Workflows alternative

Pipedream Workflows shuts down on March 31, 2027. Convert your workflows with Claude Code or Codex, and run them on Windmill.

Pipedream Workflows stops on March 31, 2027, and its data, including connected accounts, is deleted by April 30, 2027. Source

Why Windmill

Same languages

Steps in TypeScript, Python, Go or Bash, with packages installed from the imports. Your logic carries over; only the Pipedream wrapper changes.

Same triggers

Webhooks, schedules and emails, plus queues and database events.

No more shutdowns

Open source, and you can host it yourself. Nobody can turn it off for you.

Your workflows, and everything around them

Draw a workflow in the flow editor or write it as code, run it from a trigger, and build the scripts, AI agents, apps and data pipelines around it, on infrastructure you control.

summary: On-call escalation
value:
modules:
- id: check_queue
value:
type: rawscript
language: python3
content: !inline
- id: branch
value:
type: branchone
branches:
- summary: Backed up
expr: results.check_queue.depth > 50
modules:
- id: page_oncall
value:
type: rawscript
language: bun
content: !inline
- summary: Critical
expr: results.check_queue.depth > 200
modules:
- id: page_lead
value:
type: rawscript
language: bun
content: !inline
- id: wait_for_ack
suspend:
timeout: 900
/ops/oncall_escalationWorkflow
++++++++
Triggers · every minute
Check queue depth
Branch on depth
Below threshold
Backed up
Critical
TSDo nothing
TSPage on-call
TSPage the lead
Wait for ack · 15 min
Result
Click Run to try it
Workflows
Draw a DAG in the flow editor, or write it as code in Python or TypeScript, and call it as an API endpoint. Retries, approvals and parallel branches are built in.
SchedulesWebhooksKafkaSQSPostgres CDC+9 triggers →

Migrate in 3 steps

1

Export from Pipedream

Export each project as a ZIP, before April 30, 2027.

2

Convert with Claude Code or Codex

Give your coding agent the prompt from the migration guide. It adds the Pipedream migration skill and converts the export on your machine, with no account needed.

3

Push to Windmill

Connect a workspace, push the flows with their routes and schedules, and connect your accounts once. Schedules stay off until you switch over from Pipedream.

The whole migration, in a minute

Terminal
$ npx -y windmill-cli@latest init --use-default
$ curl -sL --create-dirs -o .claude/skills/migrate-from-pipedream/SKILL.md https://gist.githubusercontent.com/alpetric/efdac7864d43526d52a4df0ca5f2de18/raw/SKILL.md
$ claude "Migrate ./project_export-<id>.zip to Windmill with the migrate-from-pipedream skill"
$ npx windmill-cli workspace add
$ npx windmill-cli sync push --includes 'f/<folder>/**' --include-triggers --include-schedules

Where each Pipedream concept goes

On PipedreamOn Windmill
Code step: defineComponent({ run })A script: export async function main(...)
Python step: def handler(pd)A Python script: def main(...)
propsFunction parameters, which generate the input form
Connected account: this.slack.$authA resource passed as a typed parameter
Environment variables: process.envVariables and secrets
steps.<name>.$return_value and $.exportThe step result, read by later steps as results.<id>
$.flow.exit()Early stop
HTTP triggerWebhooks and HTTP routes
Schedule (timer) triggerSchedules
Email triggerEmail triggers
App event sourceA webhook from the app, a native trigger, or a trigger script that polls
Data storesStates, or data tables for relational data

Your code barely changes

post_to_slack.mjsBefore · Pipedream
import { WebClient } from "@slack/web-api";
export default defineComponent({
props: {
slack: { type: "app", app: "slack" },
channel: { type: "string" },
text: { type: "string" },
},
async run({ steps, $ }) {
const web = new WebClient(this.slack.$auth.oauth_access_token);
const { channel, text } = this;
return await web.chat.postMessage({ channel, text });
},
});
post_to_slack.tsAfter · Windmill
import { WebClient } from "@slack/web-api";
type Slack = { token: string };
export async function main(slack: Slack, channel: string, text: string) {
const web = new WebClient(slack.token);
return await web.chat.postMessage({ channel, text });
}

Free to start

Free to self-host. Windmill Cloud has a free plan, and Team is $10 per seat per month. See pricing.

Frequently asked questions

Build your internal platform on Windmill

Scripts, flows, apps, and infrastructure in one place.