CLI quick start
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.
- Sign up for a Cloudflare account ↗.
- Install
Node.js
↗.
Node.js version manager
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.
Workflows are defined as part of a Worker script.
To create a Workflow, use the create cloudflare
(C3) CLI tool, specifying the Workflows starter template:
npm create cloudflare@latest workflows-starter -- --template "cloudflare/workflows-starter"
This will create a new folder called workflows-tutorial
, which contains two files:
src/index.ts
- this is where your Worker script, including your Workflows definition, is defined.- wrangler.jsonc - the Wrangler configuration file for your Workers project and your Workflow.
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:
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from 'cloudflare:workers';
type Env = { // Add your bindings here, e.g. Workers KV, D1, Workers AI, etc. MY_WORKFLOW: Workflow;};
// User-defined params passed to your workflowtype Params = { email: string; metadata: Record<string, string>;};
export class MyWorkflow extends WorkflowEntrypoint<Env, Params> { async run(event: WorkflowEvent<Params>, step: WorkflowStep) { // Can access bindings on `this.env` // Can access params on `event.payload`
const files = await step.do('my first step', async () => { // Fetch a list of files from $SOME_SERVICE return { files: [ 'doc_7392_rev3.pdf', 'report_x29_final.pdf', 'memo_2024_05_12.pdf', 'file_089_update.pdf', 'proj_alpha_v2.pdf', 'data_analysis_q2.pdf', 'notes_meeting_52.pdf', 'summary_fy24_draft.pdf', ], }; });
const apiResponse = await step.do('some other step', async () => { let resp = await fetch('https://api.cloudflare.com/client/v4/ips'); return await resp.json<any>(); });
await step.sleep('wait on something', '1 minute');
await step.do( 'make a call to write that could maybe, just might, fail', // Define a retry strategy { retries: { limit: 5, delay: '5 second', backoff: 'exponential', }, timeout: '15 minutes', }, async () => { // Do stuff here, with access to the state from our previous steps if (Math.random() > 0.5) { throw new Error('API call to $STORAGE_SYSTEM failed'); } }, ); }}
export default { async fetch(req: Request, env: Env): Promise<Response> { let id = new URL(req.url).searchParams.get('instanceId');
// Get the status of an existing instance, if provided if (id) { let instance = await env.MY_WORKFLOW.get(id); return Response.json({ status: await instance.status(), }); }
// Spawn a new instance and return the ID and status let instance = await env.MY_WORKFLOW.create(); return Response.json({ id: instance.id, details: await instance.status(), }); },};
Specifically, the code above:
- Extends the Workflows base class (
WorkflowsEntrypoint
) and defines arun
method for our Workflow. - Passes in our
Params
type as a type parameter so that events that trigger our Workflow are typed. - Defines several steps that return state.
- Defines a custom retry configuration for a step.
- Binds to the Workflow from a Worker's
fetch
handler so that we can create (trigger) instances of our Workflow via a HTTP call.
You can edit this Workflow by adding (or removing) additional step
calls, changing the retry configuration, and/or making your own API calls. This Workflow template is designed to illustrate some of Workflows APIs.
Workflows are deployed via wrangler
, which is installed when you first ran npm create cloudflare
above. Workflows are Worker scripts, and are deployed the same way:
npx wrangler@latest deploy
You can run a Workflow via the wrangler
CLI, via a Worker binding, or via the Workflows REST API.
# Trigger a Workflow from the CLI, and pass (optional) parameters as an event to the Workflow.npx wrangler@latest workflows trigger workflows-tutorial --params={"email": "user@example.com", "metadata": {"id": "1"}}
Refer to the events and parameters documentation to understand how events are passed to Workflows.
You can bind to a Workflow from any handler in a Workers script, allowing you to programatically trigger and pass parameters to a Workflow instance from your own application code.
To bind a Workflow to a Worker, you need to define a [[workflows]]
binding in your Wrangler configuration:
{ "workflows": [ { "name": "workflows-starter", "binding": "MY_WORKFLOW", "class_name": "MyWorkflow" } ]}
[[workflows]]# name of your workflowname = "workflows-starter"# binding name env.MY_WORKFLOWbinding = "MY_WORKFLOW"# this is class that extends the Workflow class in src/index.tsclass_name = "MyWorkflow"
You can then invoke the methods on this binding directly from your Worker script's env
parameter. The Workflow
type has methods for:
create()
- creating (triggering) a new instance of the Workflow, returning the ID.get()
- retrieve a Workflow instance by its ID.status()
- get the current status of a unique Workflow instance.
For example, the following Worker will fetch the status of an existing Workflow instance by ID (if supplied), else it will create a new Workflow instance and return its ID:
// Import the Workflow definitionimport { WorkflowEntrypoint, WorkflowStep, WorkflowEvent} from 'cloudflare:workers';
interface Env { // Matches the binding definition in your Wrangler configuration file MY_WORKFLOW: Workflow;}
export default { async fetch(req: Request, env: Env): Promise<Response> { let id = new URL(req.url).searchParams.get('instanceId');
// Get the status of an existing instance, if provided if (id) { let instance = await env.MY_WORKFLOW.get(id); return Response.json({ status: await instance.status(), }); }
// Spawn a new instance and return the ID and status let instance = await env.MY_WORKFLOW.create(); return Response.json({ id: instance.id, details: await instance.status(), }); },};
Refer to the triggering Workflows documentation for how to trigger a Workflow from other Workers' handler functions.
The wrangler workflows
command group has several sub-commands for managing and inspecting Workflows and their instances:
- List Workflows:
wrangler workflows list
- Inspect the instances of a Workflow:
wrangler workflows instances list YOUR_WORKFLOW_NAME
- View the state of a running Workflow instance by its ID:
wrangler workflows instances describe YOUR_WORKFLOW_NAME WORKFLOW_ID
You can also view the state of the latest instance of a Workflow by using the latest
keyword instead of an ID:
npx wrangler@latest workflows instances describe workflows-starter latest# Or by ID:# npx wrangler@latest workflows instances describe workflows-starter 12dc179f-9f77-4a37-b973-709dca4189ba
The output of instances describe
shows:
- 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
- Learn more about how events are passed to a Workflow.
- Binding to and triggering Workflow instances using the Workers API.
- The Rules of Workflows and best practices for building applications using Workflows.
If you have any feature requests or notice any bugs, share your feedback directly with the Cloudflare team by joining the Cloudflare Developers community on Discord ↗.