Cloudflare Workflows Delete Instances: Wrangler Tutorial
Learn how to delete Cloudflare Workflow instances with Wrangler and Worker code, including single deletes, batches of up to 100 IDs, and testing limits.
On this page
Cloudflare added individual and batch deletion for Workflow instances on September 17, 2026, giving developers a direct way to remove an instance and its stored state without deleting the entire Workflow. The new capability is available through the Workflows API and Wrangler 4.125.0 or later, and a batch can contain up to 100 instance IDs. This tutorial builds a small TypeScript Workflow, creates test instances, deletes one with Wrangler, removes several at once, and then shows how to perform the same cleanup from Worker code.
That distinction matters because deleting a Workflow and deleting its instances are different operations. Removing the Workflow resource also removes its instances, while the new instance-level command lets you keep the Workflow definition and delete only selected executions. A running instance is stopped when it is deleted, and Cloudflare says its stored state is removed as part of the operation. Storage billing is based on average daily peak storage, so deleting stale state can also matter for long-lived applications that create many executions.
What changed with Workflow instance deletion
A Cloudflare Workflow is a durable, multi-step program that can preserve state, retry work, and continue running across pauses or interruptions. Each execution creates a Workflow instance with its own identifier and state. Before the new feature, developers who wanted to remove individual instances had fewer direct cleanup options and had to treat the lifecycle of the entire Workflow resource differently. The September 17 change adds delete() for one instance, deleteBatch() for up to 100 instances, and matching Wrangler commands for command-line cleanup.
There are two deletion paths to keep separate. In Worker code, you obtain an instance from the Workflow binding and call delete(), or call deleteBatch() on the Workflow binding when you already have several IDs. From the terminal, Wrangler accepts one or more IDs, the special value latest, or a JSON file containing instance IDs. The CLI can also target a local wrangler dev session with --local.
Set up a small Workflow for testing
Start with a normal Cloudflare Workers project because Workflows are configured as part of a Worker. Cloudflare's current getting-started guide uses the create cloudflare command, TypeScript, and a Wrangler JSON configuration file. Wrangler is installed locally in the project so the repository can keep its own CLI version instead of relying on a globally installed copy. Cloudflare currently recommends the local installation approach and supports Node.js versions in its Current, Active, and Maintenance release lines.
npm create cloudflare@latest -- workflow-delete-demo
cd workflow-delete-demo
npm i -D wrangler@latestChoose a Worker-only TypeScript project when the setup wizard asks for the template and deployment options. After the files are generated, check the installed Wrangler version before continuing:
npx wrangler --versionThe feature was introduced in Wrangler 4.125.0, so that version or newer is required for the new instance deletion command. The current Wrangler documentation recommends checking the project's local version with npx wrangler --version, which also prevents confusion when a globally installed version happens to be older.
Register the Workflow in wrangler.jsonc
Open wrangler.jsonc and define a Workflow binding. The binding connects the Worker code to a named Workflow and exposes that Workflow through a variable such as env.MY_WORKFLOW. The class_name must match the exported Workflow class in your source file. Cloudflare currently recommends wrangler.jsonc for new projects, and the current Workflows examples use the same configuration structure.
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "workflow-delete-demo",
"main": "src/index.ts",
"compatibility_date": "2026-09-18",
"observability": {
"enabled": true
},
"workflows": [
{
"name": "workflow-delete-demo",
"binding": "MY_WORKFLOW",
"class_name": "CleanupWorkflow"
}
]
}In this configuration, workflow-delete-demo is the Workflow's registered name, while MY_WORKFLOW is the variable your Worker uses to access it. The class name must be exact because Wrangler uses that value to connect the configuration to the exported class. After changing the configuration, run the type generator so the generated Env definition includes the Workflow binding.
npx wrangler typesGive the Workflow a test execution you can delete
Replace src/index.ts with a simple Workflow and an HTTP endpoint that creates instances. The Workflow below deliberately waits for five minutes, which gives you a convenient running instance to inspect and remove. The step.sleep() call is a durable pause, so Cloudflare can preserve the Workflow's state while the execution is waiting. The Worker endpoint returns the generated instance ID so you can immediately pass it to Wrangler.
import {
WorkflowEntrypoint,
type WorkflowEvent,
type WorkflowStep,
} from "cloudflare:workers";
export class CleanupWorkflow extends WorkflowEntrypoint {
async run(event: WorkflowEvent<{}>, step: WorkflowStep) {
await step.sleep("keep instance alive", "5 minutes");
```
return {
status: "completed"
};
```
}
}
export default {
async fetch(request, env): Promise {
const url = new URL(request.url);
```
if (url.pathname === "/create") {
const instance = await env.MY_WORKFLOW.create();
return Response.json({
instanceId: instance.id
});
}
if (url.pathname === "/status") {
const id = url.searchParams.get("id");
if (!id) {
return Response.json(
{ error: "Missing id" },
{ status: 400 }
);
}
const instance = await env.MY_WORKFLOW.get(id);
return Response.json(
await instance.status()
);
}
return new Response("Use /create or /status");
```
}
} satisfies ExportedHandler; Run the local development server next:
npx wrangler devWith the Worker running on the default local port, open the creation endpoint from another terminal:
curl [http://localhost:8787/create](http://localhost:8787/create)You should receive JSON containing an instanceId. Save that value because it identifies the exact Workflow execution you are about to delete. Create a second instance as well if you want to test batch deletion later. Cloudflare's current Workflows guide uses the same basic pattern of starting wrangler dev, creating an instance, and checking its returned ID. ([Cloudflare Docs][1])
Check an instance before deleting it
It is useful to inspect an instance before deleting it so you know which execution you are operating on. The Workflows CLI provides an instance description command, and the Workers API exposes status() through an instance handle. For the local project, first list the available instances with Wrangler:
npx wrangler workflows instances list workflow-delete-demo --localYou can also inspect the latest instance directly:
npx wrangler workflows instances describe workflow-delete-demo latest --localThe description output can include execution status, step state, sleep information, retries, and errors. That makes the command useful not only for confirming the ID but also for seeing whether the execution is still running before you remove it. ([Cloudflare Docs][1])
Delete one Workflow instance with Wrangler
Once you have an instance ID, the new command is straightforward. Use the Workflow name first, followed by the instance ID:
npx wrangler workflows instances delete workflow-delete-demo INSTANCE_ID --localFor example, if the returned identifier were abc-123, the command would be:
npx wrangler workflows instances delete workflow-delete-demo abc-123 --localThe command removes the selected instance and its stored state. If the instance is currently running, Cloudflare says the deletion stops its current execution without running rollback handlers. That is a meaningful difference from merely allowing a Workflow to reach the end of a sleep or other long-running step, so use instance deletion when you actually intend to end that execution.
Wrangler also provides a convenient latest shortcut. Instead of copying an identifier, you can delete the most recently created instance:
npx wrangler workflows instances delete workflow-delete-demo latest --localThe shortcut is useful for quick local testing, but it is less explicit than using a known ID in scripts or operational procedures. For cleanup automation, treating instance IDs as data and keeping them in a controlled list makes the deletion step easier to audit. The CLI documentation also supports JSON output through --json when you need machine-readable results.
Delete up to 100 instances in one batch
The batch command is the part of the new feature that becomes useful when a Workflow produces many executions. Cloudflare's API accepts between one and 100 instance IDs in a single deleteBatch() call, and Wrangler provides an equivalent command. You can put IDs directly on the command line or store them in a JSON file whose top-level value is an array of strings. If you combine positional IDs and a file, the total still cannot exceed 100 IDs. ([Cloudflare Docs][4])
Create instance-ids.json like this:
[
"abc-123",
"def-456",
"ghi-789"
]Then run:
npx wrangler workflows instances delete workflow-delete-demo
--filename ./instance-ids.json --localYou can also supply several IDs directly:
npx wrangler workflows instances delete
workflow-delete-demo abc-123 def-456 ghi-789 --localThe batch behavior has a few details worth testing rather than assuming. Cloudflare says duplicate IDs count toward the 100-ID limit, but the actual instance is deleted once and the corresponding result is repeated for each input occurrence. A nonexistent instance is reported as an error, while an invalid ID can cause the operation to fail before any instances are deleted. That distinction is useful when building cleanup jobs because "the request completed" does not necessarily mean every requested ID was successfully removed.
Delete instances directly from Worker code
The same capability is available inside your application, which is useful when cleanup follows an application event rather than an administrator running a terminal command. For one instance, obtain its handle with env.MY_WORKFLOW.get() and call delete(). For several instances, pass an array of IDs to env.MY_WORKFLOW.deleteBatch(). The batch method returns separate deleted and errors collections so the application can inspect individual results.
export async function deleteOne(env: Env, instanceId: string) {
const instance = await env.MY_WORKFLOW.get(instanceId);
await instance.delete();
return {
deleted: [instanceId],
errors: []
};
}
export async function deleteMany(env: Env, instanceIds: string[]) {
const result = await env.MY_WORKFLOW.deleteBatch(instanceIds);
return {
deleted: result.deleted,
errors: result.errors
};
}This is a better place to add application-specific rules than the terminal command itself. For example, your Worker could first determine whether an instance belongs to a tenant, whether it is old enough to remove, or whether the user initiating cleanup has permission to perform the operation. The deletion API then handles the platform-level removal while your application remains responsible for deciding which IDs are safe to pass to it. Cloudflare describes bindings as capability-granting interfaces, so the code using the binding still needs sensible authorization around consequential operations.
Test the local command, but treat local failure behavior carefully
There is a testing detail that deserves attention because it affects how much confidence you should place in a local batch-delete result. A Cloudflare Workers SDK issue filed in August 2026 reports that the local deleteBatch() implementation could incorrectly report success even when an instance did not exist, and the issue was still documented as a problem in the SDK's local Workflows implementation. That does not change the production API contract described in the current Workflows documentation, but it does mean a local test that says every deletion succeeded should not automatically be treated as proof that production will behave identically.
Use local mode to validate your command syntax, project configuration, and general workflow lifecycle, then verify important cleanup behavior against the deployed service. This is especially relevant for automation that depends on the errors array to detect missing or invalid instance IDs. A good cleanup test deliberately includes one valid ID and one nonexistent ID, records the returned result, and checks that your application handles the error path instead of quietly treating every request as successful. That gives you a test for the logic you own even when the local simulator has limitations. ([GitHub][5])
Do not confuse deletion with termination or Workflow removal
Cloudflare exposes several lifecycle operations, and they have different purposes. Deleting an instance removes its stored state and stops a running execution, while terminating an instance is a separate lifecycle operation with its own rollback behavior and semantics. Deleting the Workflow removes the Workflow resource itself and also deletes its instances. Choosing the wrong operation can therefore affect either the execution you wanted to stop or the Workflow definition you intended to keep.
For cleanup scripts, instance deletion is the narrowest of these operations because it targets selected executions while leaving the registered Workflow available for future triggers. That makes it suitable for stale test runs, completed jobs whose retained state is no longer needed, or application-controlled cleanup policies. It is not a replacement for a retention strategy, because your application still has to decide which instances qualify for deletion and when the cleanup should happen. The new API simply makes the final removal step available through both code and Wrangler.
Build cleanup around the 100-instance limit
For applications that can create thousands of Workflow instances, the 100-ID batch limit means cleanup should be treated as a paginated process rather than one enormous deletion request. Store or retrieve a manageable set of eligible instance IDs, send up to 100 in each request, inspect both the successful and failed results, and continue until the eligible set is exhausted. That approach also gives your cleanup code a natural place to record failures instead of silently discarding them. Cloudflare's current API documentation explicitly defines the 100-instance ceiling and the per-instance result structure.
A simple operational loop therefore looks like this: identify stale IDs, split them into batches of at most 100, call deleteBatch(), retain any error details, and only mark an instance as removed when it appears in the successful result. For a CLI workflow, the equivalent is generating a JSON array of IDs and running the Wrangler command repeatedly with no more than 100 IDs per file. The important part is the result handling, not the command itself.
With that structure in place, the September 17 addition becomes more than a convenient CLI command. It gives Cloudflare Workflows a clearer execution-level lifecycle: create instances when work starts, inspect them while they run, and explicitly remove state when an instance no longer needs to exist. Start by testing the Wrangler command against a single known instance, then move to batch deletion only after your application handles missing IDs and partial results correctly.
Written by


