Cloudflare will not delete the Pages project. This deletes the deployments.
The dashboard dialog links to a Wrangler guide. That guide is a loop: list IDs, delete one, repeat, and skip the one Cloudflare refuses. cf-bulk-delete runs that loop with a dry run and the protections Cloudflare actually enforces.
dashboard cf-bulk-delete
───────── ──────────────
project stuck old deployments gone
100+ deployments production left in place
delete button dead latest of each branch left in place
npm install -g cloudflare-bulk-delete
export CLOUDFLARE_API_TOKEN=your_token
export CLOUDFLARE_ACCOUNT_ID=your_account_id
cf-bulk-delete delete pages my-project --dry-run
cf-bulk-delete delete pages my-projectThe first delete only prints the plan. The second one talks to the API.
Need the click-through version:
cf-bulk-delete interactiveToken permissions are Pages Write and Workers Scripts Write. The dashboard often labels those Edit. Open the prefilled token form, or print the same link later with cf-bulk-delete token-template.
The account ID sits in the dashboard sidebar under API. It is 32 hex characters. It is not the zone ID.
Cloudflare rejects some deletes even with force=true. The tool skips those up front and treats a late rejection as skipped, not failed.
| Target | Default |
|---|---|
| Pages production deployments | kept |
| Newest Pages deployment overall | kept (--keep-latest 1) |
| Newest deployment of each branch | kept, always |
| Aliased preview deployments | deleted (force=true) |
| Worker deployment serving traffic | kept |
| Older Worker deployments | deleted |
| Worker versions | not deletable with an API token |
A Worker version is the uploaded snapshot. A deployment only decides which snapshot gets traffic. As of 2026 the versions API rejects DELETE for an API token. Rollback still covers the latest 100 versions. This tool does not pretend it can prune that history.
flowchart LR
stuck["Pages project stuck in the dashboard"] --> tool["cf-bulk-delete"]
tool --> gone["Old preview deployments deleted"]
tool --> live["Active production kept"]
tool --> branch["Latest deployment of each branch kept"]
gone --> free["Project can be deleted"]
cf-bulk-delete list
cf-bulk-delete deployments pages my-project
cf-bulk-delete delete pages my-project --dry-run
cf-bulk-delete delete pages my-project --environment preview --max-age 7
cf-bulk-delete delete pages my-project --skip-production false --keep-latest 0
cf-bulk-delete delete workers my-script --dry-run
cf-bulk-delete destroy pages my-projectdestroy removes the whole project or script. It asks you to type the name.
| Flag | What it does |
|---|---|
--dry-run |
Print the plan. Delete nothing. |
--max-age <days> |
Only consider deployments older than this. |
--environment <env> |
Pages only. production or preview. |
--skip-production false |
Include Pages production deployments. Default is to skip them. |
--keep-latest <n> |
Also protect the newest n Pages deployments. Default is 1. Use 0 to turn that off. |
--force / --no-force |
force deletes aliased non-production deployments. It is on by default. |
--batch-size <n> |
Smaller batches if the API starts answering 429. |
-y, --yes |
Skip the confirmation prompt. |
--no-skip-production is not a flag. Commander will suggest the wrong thing. The working form is --skip-production false. Same for the count: --keep-latest 0, not --keep-latest=0.
import { ServiceManager } from 'cloudflare-bulk-delete';
const manager = new ServiceManager(apiToken, accountId);
const deployments = await manager.listDeployments('pages', 'my-project');
const result = await manager.bulkDeleteDeployments('pages', 'my-project', deployments, {
skipProduction: true,
keepLatest: 1,
dryRun: true
});The extension lives in vscode/. One VSIX, no OS or CPU lock.
npm run vscode:package
code --install-extension vscode/cloudflare-bulk-delete-vscode-*.vsixThe 1.4.0 package is also attached to the GitHub release. Marketplace publishing is a separate manual step.
Invalid API token. The token needs Account Pages Write and Account Workers Scripts Write, on the right account. cf-bulk-delete token-template prints the form again.
Cannot delete an aliased deployment. Leave the default --force on. --no-force keeps aliases. Force still cannot remove the active production deployment or the latest deployment of a branch.
Too many deployments, project still stuck. Cloudflare documents this once a Pages project is over about 100 deployments. Clear the old ones, then delete the project. The live production deployment and the latest deployment of each branch remain.
Worker versions are still there. Expected. Historical deployments can go. Versions cannot, not with an API token.
429. The client already waits between calls. Drop --batch-size to 5.
Account ID not found. Copy the account ID, not the zone ID.
LOG_LEVEL=debug cf-bulk-delete listNode.js 22.14 or newer.
npm install -g cloudflare-bulk-delete
pnpm add -g cloudflare-bulk-delete
bun add -g cloudflare-bulk-deletePut the credentials in the shell or in a .env file next to where you run the command:
CLOUDFLARE_API_TOKEN=your_token
CLOUDFLARE_ACCOUNT_ID=your_account_idMIT. Rama Aditya.