
Vercel Delete Deployments
- 1 installs
- Updated June 8, 2026
- aykansal/agent-skills
Extract UIDs of failed Vercel deployments from a saved API JSON dump so you can bulk-delete ERROR (and optional CANCELED) deploys safely offline.
About
Vercel Delete Deployments is a small Node script packaged as an agent skill for solo builders who export Vercel deployment lists and need a deterministic list of broken deploy IDs before calling delete APIs or dashboard bulk actions. You point it at a JSON file captured from the Vercel deployments endpoint; it normalizes array or streamed payloads, filters ERROR deployments (and optionally CANCELED), prints a tab-separated audit line per row, and emits vercel-error-ids.txt for the next automation step. It does not call Vercel over the network by itself—reducing accidental mass deletion—so you review the file first. Ideal when ERROR deploys clutter the project history after failed previews or production pushes. Intermediate complexity assumes comfort with Node, API dumps, and Vercel UID semantics.
- Node ESM script: filter-errors.mjs reads a /v6/deployments API dump
- Detects ERROR state (and optional --include-canceled) from state or readyState
- Supports single JSON array or newline-delimited deployment chunks
- Writes sorted error UIDs to vercel-error-ids.txt in cwd
- CLI usage: node filter-errors.mjs <api-json-file> [--include-canceled]
Vercel Delete Deployments by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,172 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aykansal/agent-skills --skill vercel-delete-deploymentsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| Last updated | June 8, 2026 |
| Repository | aykansal/agent-skills ↗ |
What it does
Extract UIDs of failed Vercel deployments from a saved API JSON dump so you can bulk-delete ERROR (and optional CANCELED) deploys safely offline.
Files
Delete Vercel Deployments
Requires Vercel CLI, vercel login, and correct team scope (vercel whoami, vercel teams switch <team>).
Scripts: skills/vercel-delete-deployments/scripts/ (or .agents/skills/vercel-delete-deployments/scripts/ after npx skills add).
Choose a workflow first
| User intent | Workflow |
|---|---|
| Delete failed / error deployments | Delete by status (ERROR) — preferred |
| Delete all deployments between two IDs | Delete by ID range |
| Delete one deployment | Single delete |
Do not rely on vercel ls \| grep Error as the primary method. Output uses ANSI symbols, mixes stderr, and breaks easily on Windows. Use the API + Node scripts instead.
---
Setup (every run)
vercel whoami
# Note team slug, e.g. tryanon — use -S <team> on all commands belowResolve project name (e.g. aykansal, edutype) from the user. Confirm it is the exact Vercel project, not a sibling (edutype ≠ edutype-frontend).
Get projectId (prj_...)
vercel api "/v6/deployments?project=<project>&limit=1" -S <team> --rawRead projectId from the first deployment object. Alternatively: vercel project inspect <project> -S <team> if available.
Fetch full deployment history (required for bulk work)
cd <any-writable-dir>
vercel api "/v6/deployments?projectId=prj_xxxxx&limit=100" -S <team> --paginate --raw > vercel-deps.json- Never use
--silentonvercel api(suppresses all output). - On Windows, write to a file in the current directory, not
/tmp. - Paginated output is usually a JSON array of deployments (not
{ deployments: [] }).
Set SKILL_SCRIPTS to the scripts directory if not using the default repo layout:
SKILL_SCRIPTS=skills/vercel-delete-deployments/scripts # repo root
# SKILL_SCRIPTS=.agents/skills/vercel-delete-deployments/scripts # after npx skills add---
Delete by status (ERROR)
Use this when the user wants failed deployments removed (most common).
1. Fetch + filter
vercel api "/v6/deployments?projectId=prj_xxxxx&limit=100" -S <team> --paginate --raw > vercel-deps.json
node "${SKILL_SCRIPTS:-skills/vercel-delete-deployments/scripts}/filter-errors.mjs" vercel-deps.jsonOptional: include canceled builds: add --include-canceled.
2. Review
Script prints uid, state, target, created, url. Confirm no production deployment you need is listed.
3. Delete
vercel rm $(cat vercel-error-ids.txt | tr '\n' ' ') -y -S <team>If only one ID: vercel rm dpl_xxxxx -y -S <team>.
4. Verify
node "${SKILL_SCRIPTS:-skills/vercel-delete-deployments/scripts}/filter-errors.mjs" vercel-deps.json
vercel ls <project> -S <team> --non-interactive | head -20Delete temp files when done: vercel-deps.json, vercel-error-ids.txt, vercel-delete-ids.txt.
---
Delete by ID range (inclusive)
Use when the user gives two boundary deployment IDs (dpl_A … dpl_B). IDs are ordered by `created` timestamp, not alphabetically.
1. Confirm boundaries
vercel inspect dpl_START -S <team>
vercel inspect dpl_END -S <team>2. List range
vercel api "/v6/deployments?projectId=prj_xxxxx&limit=100" -S <team> --paginate --raw > vercel-deps.json
node "${SKILL_SCRIPTS:-skills/vercel-delete-deployments/scripts}/list-range.mjs" dpl_START dpl_END vercel-deps.jsonWrites vercel-delete-ids.txt.
3. Delete + verify
vercel rm $(cat vercel-delete-ids.txt | tr '\n' ' ') -y -S <team>
vercel ls <project> -S <team> --non-interactive | head -20Deployments newer than the start ID or older than the end ID are not removed.
---
Single delete
vercel inspect dpl_xxxxx -S <team>
vercel rm dpl_xxxxx -y -S <team>Add --safe to skip deployments that still have an active alias.
---
Safety checklist
- [ ]
-S <team>on every command - [ ] Exact project name (avoid similarly named projects in the same team)
- [ ] Inspect ERROR list for unexpected
productionrows beforevercel rm - [ ] Use
--safeif aliased production must not be removed - [ ] Re-fetch API after delete for verification (cached JSON is stale)
Common failures
| Mistake | Fix |
|---|---|
| `vercel ls \ | grep Error` misses old failures |
vercel api returns empty | Remove --silent; add -S <team>; redirect to vercel-deps.json |
| Scripts not found | Set SKILL_SCRIPTS or use path under skills/vercel-delete-deployments/scripts/ |
vercel api /v9/projects/... empty | Use /v6/deployments?project=<name>&limit=1 for projectId |
| Boundary ID "not found" | Increase limit, ensure --paginate, both IDs exist in dump |
Windows execSync empty stdout | Write API output to a file first, then run Node scripts |
Quick reference
| Goal | Command |
|---|---|
| One deployment | vercel rm dpl_xxxxx -y -S <team> |
| All ERROR in project | API fetch → filter-errors.mjs → vercel rm $(cat vercel-error-ids.txt …) |
| Range between two IDs | API fetch → list-range.mjs → vercel rm $(cat vercel-delete-ids.txt …) |
| Skip aliased prod | vercel rm … --safe |
Install
npx skills add aykansal/aykansal --skill vercel-delete-deploymentsBrowse: skills.sh
#!/usr/bin/env node
/**
* List deployment UIDs with state ERROR from a Vercel /v6/deployments API dump.
* Usage: node filter-errors.mjs <api-json-file> [--include-canceled]
* Writes IDs to vercel-error-ids.txt in cwd.
*/
import fs from "node:fs";
const args = process.argv.slice(2);
const includeCanceled = args.includes("--include-canceled");
const file = args.find((a) => !a.startsWith("--"));
if (!file) {
console.error("Usage: node filter-errors.mjs <api-json-file> [--include-canceled]");
process.exit(1);
}
const raw = fs.readFileSync(file, "utf8").trim();
let deployments = [];
try {
const parsed = JSON.parse(raw);
deployments = Array.isArray(parsed) ? parsed : parsed.deployments ?? [];
} catch {
for (const line of raw.split(/\n(?=\[|\{)/)) {
if (!line.trim()) continue;
const chunk = JSON.parse(line);
deployments.push(...(Array.isArray(chunk) ? chunk : chunk.deployments ?? []));
}
}
const isError = (d) => {
const state = String(d.state ?? d.readyState ?? "").toUpperCase();
if (state === "ERROR") return true;
if (includeCanceled && state === "CANCELED") return true;
return false;
};
const errors = deployments.filter(isError).sort((a, b) => b.created - a.created);
for (const d of errors) {
console.log(
`${d.uid}\t${d.state}\t${d.target ?? "-"}\t${new Date(d.created).toISOString()}\t${d.url ?? ""}`,
);
}
fs.writeFileSync("vercel-error-ids.txt", errors.map((d) => d.uid).join("\n"));
const label = includeCanceled ? "error/canceled" : "error";
console.error(`\n${errors.length} ${label} deployment(s) → vercel-error-ids.txt`);
#!/usr/bin/env node
/**
* List deployment UIDs between two boundary IDs (inclusive by created timestamp).
* Usage: node list-range.mjs <startId> <endId> <api-json-file>
* Writes table to stdout and IDs to vercel-delete-ids.txt in cwd.
*/
import fs from "node:fs";
const [startId, endId, file] = process.argv.slice(2);
if (!startId || !endId || !file) {
console.error("Usage: node list-range.mjs <startId> <endId> <api-json-file>");
process.exit(1);
}
const raw = fs.readFileSync(file, "utf8").trim();
let deployments = [];
try {
const parsed = JSON.parse(raw);
deployments = Array.isArray(parsed) ? parsed : parsed.deployments ?? [];
} catch {
for (const line of raw.split(/\n(?=\[|\{)/)) {
if (!line.trim()) continue;
const chunk = JSON.parse(line);
deployments.push(...(Array.isArray(chunk) ? chunk : chunk.deployments ?? []));
}
}
const byId = new Map(deployments.map((d) => [d.uid, d]));
const start = byId.get(startId);
const end = byId.get(endId);
if (!start) {
console.error(`Start deployment not found: ${startId}`);
process.exit(1);
}
if (!end) {
console.error(`End deployment not found: ${endId}`);
process.exit(1);
}
const minT = Math.min(start.created, end.created);
const maxT = Math.max(start.created, end.created);
const inRange = deployments
.filter((d) => d.created >= minT && d.created <= maxT)
.sort((a, b) => b.created - a.created);
for (const d of inRange) {
console.log(
`${d.uid}\t${d.state}\t${d.target ?? "-"}\t${new Date(d.created).toISOString()}\t${d.url ?? ""}`,
);
}
fs.writeFileSync("vercel-delete-ids.txt", inRange.map((d) => d.uid).join("\n"));
console.error(`\n${inRange.length} deployment(s) → vercel-delete-ids.txt`);