Workflows allow you to build durable, multi-step applications using the Workers platform. A Workflow can automatically retry, persist state, run for hours or days, and coordinate between third-party APIs.
You can build Workflows to post-process file uploads to R2 object storage, automate generation of Workers AI embeddings into a Vectorize vector database, or to trigger user lifecycle emails using your favorite email API.
This guide will instruct you through:
Defining your first Workflow and publishing it
Deploying the Workflow to your Cloudflare account
Running (triggering) your Workflow and observing its output
At the end of this guide, you should be able to author, deploy and debug your own Workflows applications.
Use a Node version manager like Volta ↗ or nvm ↗ to avoid permission issues and change Node.js versions. Wrangler, discussed later in this guide, requires a Node version of 16.17.0 or later.
1. Define your Workflow
To create your first Workflow, use the create cloudflare (C3) CLI tool, specifying the Workflows starter template:
This will create a new folder called workflows-starter.
Open the src/index.ts file in your text editor. This file contains the following code, which is the most basic instance of a Workflow definition:
A Workflow definition:
Defines a run method that contains the primary logic for your workflow.
Has at least one or more calls to step.do that encapsulates the logic of your Workflow.
Allows steps to return (optional) state, allowing a Workflow to continue execution even if subsequent steps fail, without having to re-run all previous steps.
A single Worker application can contain multiple Workflow definitions, as long as each Workflow has a unique class name. This can be useful for code re-use or to define Workflows which are related to each other conceptually.
Each Workflow is otherwise entirely independent: a Worker that defines multiple Workflows is no different from a set of Workers that define one Workflow each.
2. Create your Workflows steps
Each step in a Workflow is an independently retriable function.
A step is what makes a Workflow powerful, as you can encapsulate errors and persist state as your Workflow progresses from step to step, avoiding your application from having to start from scratch on failure and ultimately build more reliable applications.
A step can execute code (step.do) or sleep a Workflow (step.sleep).
If a step fails (throws an exception), it will be automatically be retried based on your retry logic.
If a step succeeds, any state it returns will be persisted within the Workflow.
At its most basic, a step looks like this:
Each call to step.do accepts three arguments:
(Required) A step name, which identifies the step in logs and telemetry
(Required) A callback function that contains the code to run for your step, and any state you want the Workflow to persist
(Optional) A StepConfig that defines the retry configuration (max retries, delay, and backoff algorithm) for the step
When trying to decide whether to break code up into more than one step, a good rule of thumb is to ask “do I want all of this code to run again if just one part of it fails?“. In many cases, you do not want to repeatedly call an API if the following data processing stage fails, or if you get an error when attempting to send a completion or welcome email.
For example, each of the below tasks is ideally encapsulated in its own step, so that any failure — such as a file not existing, a third-party API being down or rate limited — does not cause your entire program to fail.
If a subsequent step fails, your Workflow can retry from that step, using any state returned from a previous step. This can also help you avoid unnecessarily querying a database or calling an paid API repeatedly for data you have already fetched.
3. Configure your Workflow
Before you can deploy a Workflow, you need to configure it.
Open the wrangler.toml file at the root of your workflows-starter folder, which contains the following [[workflows]] configuration:
This configuration tells the Workers platform which JavaScript class represents your Workflow, and sets a binding name that allows you to run the Workflow from other handlers or to call into Workflows from other Workers scripts.
4. Bind to your Workflow
We have a very basic Workflow definition, but now need to provide a way to call it from within our code. A Workflow can be triggered by:
Return to the src/index.ts file we created in the previous step and add a fetch handler that binds to our Workflow. This binding allows us to create new Workflow instances, fetch the status of an existing Workflow, pause and/or terminate a Workflow.
The code here exposes a HTTP endpoint that generates a random ID and runs the Workflow, returning the ID and the Workflow status. It also accepts an optional instanceId query parameter that retrieves the status of a Workflow instance by its ID.
Review your Workflow code
Before you deploy, you can review the full Workflows code and the fetch handler that will allow you to trigger your Workflow over HTTP:
5. Deploy your Workflow
Deploying a Workflow is identical to deploying a Worker.
A Worker with a valid Workflow definition will be automatically registered by Workflows. You can list your current Workflows using Wrangler:
6. Run and observe your Workflow
With your Workflow deployed, you can now run it.
A Workflow can run in parallel: each unique invocation of a Workflow is an instance of that Workflow.
An instance will run to completion (success or failure).
Deploying newer versions of a Workflow will cause all instances after that point to run the newest Workflow code.
To trigger our Workflow, we will use the wrangler CLI and pass in an optional --payload. The payload will be passed to your Workflow’s run method handler as an Event.
To inspect the current status of the Workflow instance we just triggered, we can either reference it by ID or by using the keyword latest:
From the output above, we can inspect:
The status (success, failure, running) of each step
Any state emitted by the step
Any sleep state, including when the Workflow will wake up
Retries associated with each step
Errors, including exception messages
In the previous step, we also bound a Workers script to our Workflow. You can trigger a Workflow by visiting the (deployed) Workers script in a browser or with any HTTP client.