Products · Developer platform
Workflows
Build durable, multi-step applications using the Workers platform
Pricing and limits
Pricing
As of Nov 3, 2026, from Cloudflare's docs, last updated there Sep 21, 2026. Licensed CC BY 4.0; navigation removed.
Note
Workflows is included in both the Free and Paid Workers plans. Billing for Workflows steps and storage will apply starting August 10th, 2026.
Workflows uses Workers Standard pricing for CPU time and requests. Workflows are billed on four dimensions:
- CPU time: the total amount of compute (measured in milliseconds) consumed by a given Workflow.
- Requests (invocations): the number of Workflow invocations. Subrequests made from a Workflow do not incur additional request costs.
- Storage: the total amount of storage (measured in GB) persisted by your Workflows.
- Steps: the number of steps executed by your Workflows.
A Workflow that is waiting on a response to an API call, paused as a result of calling step.sleep, or otherwise idle, does not incur CPU time.
Note
Step count does not include rollback handlers or retries.
Workflows pricing
| Unit | Workers Free | Workers Paid |
|---|---|---|
| Requests (millions) | 100,000 per day (shared with Workers requests) | 10 million included per month + $0.30 per additional million |
| CPU time (ms) | 10 milliseconds of CPU time per invocation | 30 million CPU milliseconds included per month + $0.02 per additional million CPU milliseconds |
| Storage (GB-mo) | 1 GB-month | 1 GB-month included + $0.20/ GB-month |
| Steps | 3,000 per day | 500,000 included per month + $0.80/ additional 100,000 per month |
Cloudflare will not bill step and storage usage before the start date announced in the Workflows billing changelog.
CPU limits
You can increase the CPU limit available to your Workflow instances up to 5 minutes per Workflow by setting the limits.cpu_ms property in your Wrangler configuration.
Storage Usage
Storage is billed using gigabyte-month (GB-month) as the billing metric, identical to Durable Objects SQL storage. A GB-month is calculated by averaging the peak storage per day over a billing period (30 days).
- Storage is calculated across all instances, and includes running, errored, sleeping, and completed instances.
- By default, instance state is retained for 3 days on the Free plan and 30 days on the Paid plan.
- If you do not need to retain state for errored or completed Workflows, you can set a shorter retention period for every instance of a Workflow with
default_retentionin your Wrangler configuration, or per instance with theretentionoption inWorkflowInstanceCreateOptions. - Deleting instances via the Workers API, Wrangler CLI, REST API, or dashboard will free up storage. It may take a few minutes for storage limits to update.
An instance that attempts to store state when you have reached the storage limit on the Free plan will throw an error.
Frequently Asked Questions
Frequently asked questions related to Workflows pricing:
Are there additional costs for Workflows?
Yes. Workflows are priced based on the same compute (CPU time) and requests (invocations) as Workers, as well as storage (state from a Workflow) and steps.
Are Workflows available on the Workers Free plan?
Yes.
What is a Workflow invocation?
A Workflow invocation is when you trigger a new Workflow instance: for example, via the Workers API, wrangler CLI, or REST API. Steps within a Workflow are not invocations.
How do Workflows show up on my bill?
Workflows are billed as Workers, and share the same CPU time and request SKUs. Workflows billing also includes storage and step usage.
Are there any limits to Workflows?
Refer to the published limits documentation.
Limits
As of Nov 3, 2026, from Cloudflare's docs, last updated there Sep 21, 2026. Licensed CC BY 4.0; navigation removed.
Limits that apply to authoring, deploying, and running Workflows are detailed below.
Many limits are inherited from those applied to Workers scripts and as documented in the Workers limits documentation.
Note
Workflows cannot be deployed to Workers for Platforms namespaces, as Workflows do not support Workers for Platforms.
| Feature | Workers Free | Workers Paid |
|---|---|---|
| Workflow class definitions per script | 3MB max script size per Worker size limits | 10MB max script size per Worker size limits |
| Total scripts per account | 100 | 500 (shared with Worker script limits |
| Compute time per step 1 | 10 ms | 30 seconds (default) / configurable to 5 minutes of active CPU time |
| Duration (wall clock) per step 1 | Unlimited | Unlimited - for example, waiting on network I/O calls or querying a database |
| Maximum non-stream step result per step 2 | 1MiB (2^20 bytes) | 1MiB (2^20 bytes) |
| Maximum event payload size | 1MiB (2^20 bytes) | 1MiB (2^20 bytes) |
| Maximum state that can be persisted per Workflow instance 3 | 100MB | 1GB |
Maximum step.sleep duration |
365 days (1 year) | 365 days (1 year) |
| Maximum steps per Workflow 4 | 1,024 | 10,000 (default) / configurable up to 25,000 |
| Maximum Workflow executions | 100,000 per day shared with Workers daily limit | Unlimited |
| Concurrent Workflow instances (executions) per account 5 | 100 | 50,000 |
| Maximum Workflow instance creation rate 6 | 100 per second 7 | 300 per second per account 7, 100 per second per workflow |
| Maximum number of queued instances | 100,000 | 2,000,000 |
| Retention limit for completed Workflow instance state | 3 days | 30 days 8 |
| Maximum length of a Workflow name 9 | 64 characters | 64 characters |
| Maximum length of a Workflow instance ID 9 | 100 characters | 100 characters |
| Maximum number of subrequests per Workflow instance | 50/request | 10,000/request (default) / configurable up to 10 million |
| Maximum number of retries per step | 10,000 | 10,000 |
Need a higher limit?
To request an adjustment to a limit, complete the Limit Increase Request Form ↗︎. If the limit can be increased, Cloudflare will contact you with next steps.
In JavaScript Workflows, if you need to persist large binary output from a step, return a ReadableStream<Uint8Array>. Streamed outputs still count toward the per-instance storage limit, so store very large or long-lived artifacts in external storage such as R2 and return a reference when appropriate.
waiting instances do not count towards instance concurrency limits
Instances that are in a waiting state — either sleeping via step.sleep, waiting for a retry, or waiting for an event via step.waitForEvent — do not count towards concurrency limits. This means you can have millions of Workflow instances sleeping or waiting for events simultaneously, as only actively running instances count toward the 10,000 concurrent instance limit. However, if there are 10,000 concurrent instances actively running, an instance that has been in a waiting state will be queued instead of resuming immediately. When an instance transitions from running to waiting, other queued instances will be scheduled (usually the oldest queued instance, on a best-effort basis). This state transition may not occur if the wait duration is very short.
For example, consider a Workflow that does some work, waits for 30 days, and then continues with more work:
src/index.tsts
import {
WorkflowEntrypoint,
WorkflowStep,
WorkflowEvent,
} from "cloudflare:workers";
type Env = {
MY_WORKFLOW: Workflow;
};
export class MyWorkflow extends WorkflowEntrypoint<Env> {
async run(event: WorkflowEvent<unknown>, step: WorkflowStep) {
await step.do("initial work", async () => {
let resp = await fetch("https://api.cloudflare.com/client/v4/ips");
return await resp.json<any>();
});
await step.sleep("wait 30 days", "30 days");
await step.do(
"make a call to write that could maybe, just might, fail",
{
retries: {
limit: 5,
delay: "5 seconds",
backoff: "exponential",
},
timeout: "15 minutes",
},
async () => {
if (Math.random() > 0.5) {
throw new Error("API call to $STORAGE_SYSTEM failed");
}
},
);
}
}
While a given Workflow instance is waiting for 30 days, it will transition to the waiting state, allowing other queued instances to run if concurrency limits are reached.
Cron-triggered instances on Workers Paid
On Workers Paid, Workflow instances created by schedules can run for up to one hour per cron firing without consuming a Workflow concurrency slot.
After that budget is used, the instance yields and enters the normal concurrency queue. It resumes when a concurrency slot is available. The instance does not fail, time out, or terminate because it used this cron concurrency budget.
The following limits apply to Workflow schedules:
| Limit | Value |
|---|---|
Maximum number of schedules (cron expressions) per account |
100 |
| Maximum length of a cron expression | 256 characters |
Increasing Workflow step limits
Each Workflow instance supports 10,000 steps by default, but this can be increased up to 25,000 steps in your Wrangler configuration. Refer to Workflow step limits for more information.
Increasing Workflow CPU limits
Workflows are Worker scripts, and share the same per invocation CPU limits as any Workers do. Note that CPU time is active processing time: not time spent waiting on network requests, storage calls, or other general I/O, which don't count towards your CPU time or Workflows compute consumption.
If your Workflow exceeds its CPU time limit, it will throw the following error:
Error: Worker exceeded CPU time limit.
This will appear as exceededCpu in wrangler tail outcomes and as exceededResources in Workers metrics.
By default, the maximum CPU time per Workflow invocation is set to 30 seconds, but can be increased for all invocations associated with a Workflow definition by setting limits.cpu_ms in your Wrangler configuration:
{
// ...rest of your configuration...
"limits": {
"cpu_ms": 300000, // 300,000 milliseconds = 5 minutes
},
// ...rest of your configuration...
}
[limits]
cpu_ms = 300_000
To learn more about CPU time and limits, review the Workers documentation.
Increasing Workflow subrequest limits
A subrequest is any request that a Workflow makes to either Internet resources using the Fetch API or requests to other Cloudflare services like R2, KV, or D1. Because Workflows are long-running and often make many calls to external services or Cloudflare APIs, they can exceed the default subrequest limit.
If your Workflow exceeds its subrequest limit, it will throw the following error:
Error: Too many subrequests.
This will appear as exceededResources in Workers metrics and as exception in wrangler tail outcomes.
By default, the maximum number of subrequests per Workflow instance is 10,000 on Workers Paid plans, but this can be increased up to 10 million by setting limits.subrequests in your Wrangler configuration:
{
// ...rest of your configuration...
"limits": {
"subrequests": 10000000, // 10 million (maximum)
},
// ...rest of your configuration...
}
[limits]
subrequests = 10_000_000
Workers on the free plan remain limited to 50 external subrequests and 1,000 subrequests to Cloudflare services per invocation.
To learn more about subrequest limits, review the Workers documentation.
Wall time limits by invocation type
Wall time (also called wall-clock time) is the total elapsed time from the start to end of an invocation, including time spent waiting on network requests, I/O, and other asynchronous operations. This is distinct from CPU time, which only measures time the CPU spends actively executing your code.
The following table summarizes the wall time limits for different types of Worker invocations across the developer platform:
| Invocation type | Wall time limit | Details |
|---|---|---|
| Incoming HTTP request | Unlimited | No hard limit while the client remains connected. Workers requests are subject to the grace period for runtime updates. A Worker that is still streaming a response body remains active. waitUntil() extends execution for up to 30 seconds after the response or disconnect. |
| Cron Triggers | 15 minutes | Scheduled Workers have a maximum wall time of 15 minutes per invocation. |
| Queue consumers | 15 minutes | Each consumer invocation has a maximum wall time of 15 minutes. |
| Durable Object alarm handlers | 15 minutes | Alarm handler invocations have a maximum wall time of 15 minutes. |
| Durable Objects (RPC / HTTP) | Unlimited | No hard limit while the caller stays connected to the Durable Object. Durable Objects remain active while a request, RPC call, response stream, WebSocket, or pending I/O is in flight. |
| Workflows (per step) | Unlimited | Each step can run for an unlimited wall time. Individual steps are subject to the configured CPU time limit. |
Footnotes
- A Workflow instance can run forever, as long as each step does not take more than the CPU time limit and the maximum number of steps per Workflow is not reached. ↩ ↩2
- Applies to non-stream
step.do()return values. In JavaScript Workflows,ReadableStream<Uint8Array>is also a supported serializable return type for larger binary output. ↩ - This total includes persisted bytes from streamed step outputs returned from JavaScript
step.do()calls. ↩ step.sleepdoes not count towards the maximum steps limit ↩- Only instances with a
runningstate count towards the concurrency limits. Instances in thewaitingstate are excluded from these limits. Workers Paid cron-triggered Workflow instances have a separate one-hour cron concurrency budget per firing. ↩ - Each instance created or restarted counts towards this limit ↩
- Workflows will return a HTTP 429 rate limited error if you exceed the rate of new Workflow instance creation. ↩ ↩2
- Workflow instance state and logs will be retained for 3 days on the Workers Free plan and for 30 days on the Workers Paid plan. You can retain instances for a shorter period by setting
default_retentionon the Workflow binding, orretentionon an individual instance. ↩ - Match pattern: _
^[a-zA-Z0-9_][a-zA-Z0-9-_]\*$_ ↩ ↩2
Timeline
October 2026
- Increased Durable Objects, D1 and Workflows Error Rates Incident
Minor impact. Resolved Oct 29, 2026, 16:33 UTC.
- Increased Errors for Durable Objects in the Eastern North America region Incident
Minor impact. Resolved Oct 28, 2026, 11:10 UTC.
- Increased Errors for Durable Objects in the Eastern North America region Incident
Minor impact. Resolved Oct 28, 2026, 03:28 UTC.
- Restrict Workflows to a jurisdiction
You can now restrict a Workflow to a jurisdiction. Its instances only run and store data within that jurisdiction, which helps you comply with data localization regulations such as GDPR ↗︎ or FedRAMP ↗︎. Set jurisdiction on a workflows binding, or on a Workflow declared in exports: { "workflows": [ { "name": "my-workflow", "binding": "MY_WORKFLOW", "class_name": "MyWorkflow", "jurisdiction": "eu"…
- Create Workflow instance batches by count or list
createBatch() now accepts an options object that creates up to 100 Workflow instances in one call. The result lists the created instances and explains why any others were not created. To use this form in local development and get its types from wrangler types, use Wrangler 4.148.0 or later. To create instances that share the same options, pass count. Each instance receives a generated ID: const r…
September 2026
- Call Workflows declared in `exports` through `ctx.exports`
A Worker can now call the Workflows it declares in the exports field of its Wrangler configuration through ctx.exports. You no longer need a workflows binding to call a Workflow from the Worker that defines it. Each Workflow is keyed by class name, and has the same API as a Workflow binding: src/index.jsjsexport default { async fetch(request, env, ctx) { const instance = await ctx.exports.MyWorkf…
- Declare Workflows in the `exports` configuration
You can now declare the Workflows a Worker defines in the exports field of your Wrangler configuration file. Previously, a Worker could only define a Workflow through a workflows binding, even when the Worker never called the Workflow itself. Key each entry by the name of the class that extends WorkflowEntrypoint: { "exports": { "MyWorkflow": { "type": "workflow", "name": "my-workflow", "limits":…
- Delete Workflow instances individually or in batches
You can now delete one or up to 100 Workflow instances and their stored state via the Workflows API or Wrangler 4.125.0 and later. Deleting an instance frees its stored state and stops its current execution. Storage billing is based on the average daily peak. Delete one instance by calling delete() on its handle: const instance = await env.MY_WORKFLOW.get("instance-abc"); await instance.delete();…
- Stream Workflow instance events in your Worker or via the API with .subscribe()
You can now stream Workflow instance events via WorkflowInstance.subscribe() and the GET /subscribe API endpoint. Workers and HTTP clients can react to workflow and step events, including attempts, sleeps, waits, and rollbacks, without polling for instance status. A subscription first streams the entire event history of the Workflow instance. After streaming past events, the subscription waits fo…
- Default instance retention for new Workflows on Workers Paid is seven days
Workflows created on or after September 10, 2026, on the Workers Paid plan retain completed and errored instance state for seven days by default (previously 30 days). The seven day default helps to reduce storage costs by default. The maximum retention limit remains 30 days. The retention period for existing Workflows is unchanged. The Workers Free plan retains its three-day default and limit. To…
August 2026
- Build and deploy Artifacts repos on every push
You can now run your CI/CD pipeline on your Artifacts repo by defining a CI Workflow with the CI SDK ↗︎, automatically triggered on Artifacts push events. This allows you to: Automatically build and deploy application code stored in Artifacts. Run linting, type checking, tests, and other checks on every push. Reuse dependencies when the lockfile (i.e. pnpm-lock.yaml) has not changed. Stop deploym…
July 2026
- Workflows now supports delay functions when retrying
With Workflows, you can configure built-in retry behavior for each step. Previously, you could configure step retries with fixed delay durations, such as seconds, minutes, or hours, and backoff strategies such as constant, linear, or exponential. Step retries now support dynamic delay functions. Instead of choosing only a base delay and backoff strategy, pass a function to retries.delay and calcu…
- Workflows pricing adds per-step billing. Step and storage billing to start no earlier than August 10, 2026.
Workflows pricing now includes per-step billing. Requests and CPU time billing have been enabled since the initial public beta and is not changing. Workflows adds step billing A step is each unit of work executed by a Workflow, including step operations such as sleeping or waiting for events. You can query Workflows analytics, including stepCount for a Workflow instance, with the GraphQL Analytic…
June 2026
- Workflows rollback handlers now include step context
Workflows makes it easier to build reliable multi-step applications that can recover when downstream systems fail. Rollback handlers now receive the original step context via a ctx object for the step being rolled back. This includes ctx.step.name, ctx.step.count, ctx.attempt, and the step config with defaults applied. The step configuration includes the retry and timeout settings used for that s…
- Rollback support now available in Workflows
Workflows now supports saga-style rollbacks, allowing you to add compensating logic to each step.do() in case of downstream failures. If the instance fails, the rollback handlers will execute in reverse step-start order. This is useful for multi-step operations that touch external systems, such as inventory reservations, payment authorization, ticket creation, or infrastructure provisioning. Inst…
- Schedule Workflow instances directly from your Workflow binding
You can now attach cron schedules directly to a Workflow binding in wrangler.jsonc. Each scheduled run creates a new Workflow instance automatically, so you do not need to define a separate Worker with a scheduled handler just to trigger your Workflow on an interval. For example, you can configure hourly, every-15-minute, or weekday schedules on the same Workflow: { "workflows": [ { "name": "my-s…
May 2026
- Run Workflows inside Dynamic Workers with the @cloudflare/dynamic-workflows library
You can now use @cloudflare/dynamic-workflows ↗︎ to run a Workflow inside a Dynamic Worker, ensuring durable execution for code that is loaded at runtime. The Worker Loader loads Dynamic Workers on demand, which previously made durability challenging. Even within a Dynamic Worker, a Workflow might sleep for hours or days between steps, and by the time it resumes, the original Dynamic Worker code…
April 2026
- Additional step context and ReadableStream support now available in Workflows step.do()
Workflows now provides additional context inside step.do() callbacks and supports returning ReadableStream to handle larger step outputs. Step context properties The step.do() callback receives a context object with new properties alongside attempt: step.name — The name passed to step.do() step.count — How many times a step with that name has been invoked in this instance (1-indexed) Useful when…
- Increased concurrency, creation rate, and queued instance limits for Workflows instances
Workflows limits have been raised to the following: Limit Previous New Concurrent instances (running in parallel) 10,000 50,000 Instance creation rate (per account) 100/second per account 300/second per account, 100/second per workflow Queued instances per Workflow 1 1 million 2 million These increases apply to all users on the Workers Paid plan. Refer to the Workflows limits documentation for mo…
- All Wrangler commands for Workflows now support local development
All wrangler workflows commands now accept a --local flag to target a Workflow running in a local wrangler dev session instead of the production API. You can now manage the full Workflow lifecycle locally, including triggering Workflows, listing instances, pausing, resuming, restarting, terminating, and sending events: npx wrangler workflows list --local npx wrangler workflows trigger my-workflow…
March 2026
- Workflow instances now support pause(), resume(), restart(), and terminate() methods in local development
Workflow instance methods pause(), resume(), restart(), and terminate() are now available in local development when using wrangler dev. You can now test the full Workflow instance lifecycle locally: const instance = await env.MY_WORKFLOW.create({ id: "my-instance-id", }); await instance.pause(); // pauses a running workflow instance await instance.resume(); // resumes a paused instance await inst…
- Workflow steps now expose retry attempt number via step context
Cloudflare Workflows allows you to configure specific retry logic for each step in your workflow execution. Now, you can access which retry attempt is currently executing for calls to step.do(): await step.do("my-step", async (ctx) => { // ctx.attempt is 1 on first try, 2 on first retry, etc. console.log(`Attempt ${ctx.attempt}`); }); You can use the step context for improved logging & observabil…
- Workflows step limit increased to 25,000 steps per instance
Each Workflow on Workers Paid now supports 10,000 steps by default, configurable up to 25,000 steps in your wrangler.jsonc file: { "workflows": [ { "name": "my-workflow", "binding": "MY_WORKFLOW", "class_name": "MyWorkflow", "limits": { "steps": 25000 } } ] } Previously, each instance was limited to 1,024 steps. Now, Workflows can support more complex, long-running executions without the addition…
February 2026
- Visualize your Workflows in the Cloudflare dashboard
Cloudflare Workflows now automatically generates visual diagrams from your code Your Workflow is parsed to provide a visual map of the Workflow structure, allowing you to: Understand how steps connect and execute Visualize loops and nested logic Follow branching paths for conditional logic You can collapse loops and nested logic to see the high-level flow, or expand them to see every step. Workfl…
- Agents SDK v0.3.7: Workflows integration, synchronous state, and scheduleEvery()
The latest release of the Agents SDK ↗︎ brings first-class support for Cloudflare Workflows, synchronous state management, and new scheduling capabilities. Cloudflare Workflows integration Agents excel at real-time communication and state management. Workflows excel at durable execution. Together, they enable powerful patterns where Agents handle WebSocket connections while Workflows handle long-…
October 2025
- Increased Workflows instance and concurrency limits
We've raised the Cloudflare Workflows account-level limits for all accounts on the Workers paid plan: Instance creation rate increased from 100 workflow instances per 10 seconds to 100 instances per second Concurrency limit increased from 4,500 to 10,000 workflow instances per account These increases mean you can create new instances up to 10x faster, and have more workflow instances concurrently…
August 2025
- Build durable multi-step applications in Python with Workflows (now in beta)
You can now build Workflows using Python. With Python Workflows, you get automatic retries, state persistence, and the ability to run multi-step operations that can span minutes, hours, or weeks using Python’s familiar syntax and the Python Workers runtime. Python Workflows use the same step-based execution model as JavaScript Workflows, but with Python syntax and access to Python’s ecosystem. Py…
June 2025
- Run AI-generated code on-demand with Code Sandboxes (new)
AI is supercharging app development for everyone, but we need a safe way to run untrusted, LLM-written code. We’re introducing Sandboxes ↗︎, which let your Worker run actual processes in a secure, container-based environment. import { getSandbox } from "@cloudflare/sandbox"; export { Sandbox } from "@cloudflare/sandbox"; export default { async fetch(request: Request, env: Env) { const sandbox = g…
April 2025
- Workflows is now Generally Available
Workflows is now Generally Available (or "GA"): in short, it's ready for production workloads. Alongside marking Workflows as GA, we've introduced a number of changes during the beta period, including: A new waitForEvent API that allows a Workflow to wait for an event to occur before continuing execution. Increased concurrency: you can run up to 4,500 Workflow instances concurrently — and this wi…
February 2025
- Concurrent Workflow instances limits increased.
Workflows now supports up to 4,500 concurrent (running) instances, up from the previous limit of 100. This limit will continue to increase during the Workflows open beta. This increase applies to all users on the Workers Paid plan, and takes effect immediately. Review the Workflows limits documentation and/or dive into the get started guide to start building on Workflows.
- Build AI Agents with Example Prompts
We've added an example prompt to help you get started with building AI agents and applications on Cloudflare Workers, including Workflows, Durable Objects, and Workers KV. You can use this prompt with your favorite AI model, including Claude 3.5 Sonnet, OpenAI's o3-mini, Gemini 2.0 Flash, or Llama 3.3 on Workers AI. Models with large context windows will allow you to paste the prompt directly: pr…
January 2025
- Increased Workflows limits and improved instance queueing.
Workflows (beta) now allows you to define up to 1024 steps. sleep steps do not count against this limit. We've also added: instanceId as property to the WorkflowEvent type, allowing you to retrieve the current instance ID from within a running Workflow instance Improved queueing logic for Workflow instances beyond the current maximum concurrent instances, reducing the cases where instances are st…
October 2024
- Workflows is now in open beta
Workflows is now in open beta, and available to any developer a free or paid Workers plan. Workflows allow you to build multi-step applications that can automatically retry, persist state and run for minutes, hours, days, or weeks. Workflows introduces a programming model that makes it easier to build reliable, long-running tasks, observe as they progress, and programmatically trigger instances b…