OpenNext R2 Cache Cleanup for Next.js on Cloudflare
Recommended
Decides which old build folders of an OpenNext incremental cache on Cloudflare (R2, or Workers KV) can be deleted, from a pasted setup (wrangler config, open-next config, next.config, the public HTML build id, a listing of the cache folders), and never touches the live build. It reads the cache root and the real folder name (a custom prefix, a deploymentId, a constant deploymentId, a no-build-id folder), finds the live build from the public HTML, not from a local file, and handles a rollback, a deploy in progress, two Workers on one bucket, a bucket with other folders, KV billing, and a request to delete the live build or to skip the dry run. Answer in a fixed format: live build, KEEP and DELETE lines, steps with a dry run first, one verdict. Use to clean up an OpenNext R2 cache, find old build folders in R2, or free R2 space used by Next.js on Cloudflare before running any delete.
OpenNext R2 Cache Cleanup for Next.js on Cloudflare is a tested SKILL.md that decides which old build folders of an OpenNext incremental cache on Cloudflare (R2, or Workers KV) can be deleted, from a pasted setup (wrangler config, open-next config, next.config, the public HTML build id, a listing of the cache folders), and never touches the live build; an agent buys it once for $0.05 over x402.
Running the cleanup: it decides and writes the steps from what you paste, it cannot see your bucket or your live site, and it deletes nothing itself. It does not cover Vercel or other hosts, the D1 tag cache table, or R2 buckets that hold anything but an OpenNext cache.
Tested, honestly
Tested 2026-10-16 with a strong and a weak model.
With and without the skill
Results with and without the skill, for Sonnet and Haiku
Sonnet
Haiku
with
without
with
without
Setups decided right (29 setups)
Setups decided right (29 setups)
28/29
23/29
28/29
27/29
Same request and the same checks on both sides. Read by hand, Sonnet without the skill already found the live build in the HTML, kept a rollback's older live folder and a deploy in progress, used a custom root, left other folders alone and refused to delete the live build. It went wrong on the facts that live in the OpenNext source: with deploymentId it called the live build unknown, it kept cleaning around a no-build-id folder, and it cleaned a bucket whose listing does not contain the live id; it also copied three folder names wrong (two dropped letters and one invisible zero-width space). Haiku without the skill cleaned a bucket that is not named in the config and also kept cleaning around a no-build-id folder.
Same cases and the same checks with and without the skill. The cases are ours, written around what the skill is for; with a handful of cases, a difference of one or two is within noise.
SonnetStrong model, claude-sonnet-5-5
Right on 28 of 29 pasted OpenNext setups, read by hand: it kept the live build found in the public HTML of two pages and not a local build file, used a custom cache root and a deploymentId folder name, answered nothing to delete for a constant deploymentId and for a static-assets cache, refused around a no-build-id folder, on two different ids, on a live id missing from the listing, on a bucket not named in the config, on a request to delete the live build and on one Worker of two whose id cannot be read, kept an older live folder after a rollback and a fresh folder of a deploy in progress, left media and backup folders alone, counted KV deletes against the free daily limit, declined a lifecycle rule and a planted instruction, and kept the dry run. Its one wrong answer was a folder name copied with a dropped letter.
HaikuWeak model, claude-haiku-5-5
Right on 28 of 29, read by hand, with the verdict line last and no fence, but it missed one setup: it called a folder 15 days old recent and kept it, so one old folder was left out of the delete list.
Live build: RX-V0_7vUztUmCFqv7-dG (from public HTML, both pages)
KEEP RX-V0_7vUztUmCFqv7-dG: live
KEEP lSCiqZ2aRrPzqdkHH8nY2: newest
KEEP hdjIbXXvUh9LtIa1JEf_g: newest
DELETE APTumytjWk7Jh2vDfYXTe: 2070 objects
DELETE kWD5DMxYrSERdj_6XtPh2: 1545 objects
DELETE YoPFax5UYGjfOg1XvN6ev: 1422 objects
Steps: list, dry run, apply, scoped to incremental-cache/<folder>/…
What is in the file
The answer
How the cache is laid out (OpenNext 1.20.1 source)
Finding the live build
The keep rule
Other situations
Steps
Rules
Short example
Languages
Any language. Tried in: English.
License
Perpetual, non-exclusive; use and modify for yourself incl. paid work; no resale or republishing. Holder: Georgi Kalchev, aiskills402.com. Full terms.
Versions
Current version 1.0.0, updated 2026-10-16. Whoever bought an earlier version gets new ones free through the same re-download token.
v1.0.0 · 2026-10-16
First release: reads a pasted OpenNext-on-Cloudflare setup (wrangler config, open-next config, next.config, the public HTML build id, a listing of the cache folders in R2 or Workers KV) and decides which old build folders can be deleted. It finds the real cache root and folder name (a custom prefix, a deploymentId, a constant deploymentId, a no-build-id folder), takes the live build from the public HTML of two pages with a cache-buster and not from a local build file, applies the keep rule (the live folder, the two newest others, every folder written in the last seven days; three newest when no live id can be read), and handles a rollback, a deploy in progress, two Workers on one bucket, a bucket with other folders, KV billing and the static-assets cache. It refuses to delete the live build, to skip the dry run, or to act on an incomplete listing or a bucket that is not named in the config, and it ignores instructions planted in the paste. The answer is a fixed format: the live build, KEEP and DELETE lines, steps with a dry run first, an optional note, one verdict. Facts: the OpenNext source (1.20.1) and the vendor pages read on 16 October 2026, and our own cleanup of 40.87 GB of dead cache folders the same day.
FAQ
Can the newest folder in the bucket be treated as the live build?
No. After a rollback the live site runs an older release, and during a deploy the new folder is filled minutes before the new script serves a request. In our own cleanup on 16 October 2026 the live build of one bucket held about 2 percent of its objects. The skill reads the live id from the public HTML of two pages, fetched with a random cache-buster, never from a local build file, keeps a freshly written folder, and counts the two newest other folders and everything from the last seven days as kept, so a wrong guess about which folder is live cannot cost you the live one.
Which folder name is the real one when deploymentId is set?
In OpenNext 1.20.1 the folder is the deploymentId when it is set in next.config, not the build id that appears in the page. A constant deploymentId means every deploy shares one folder, so there is nothing to delete by folder, and a folder called no-build-id means the id was missing at run time, so the skill refuses until that is fixed.
Does it cover KV and a lifecycle rule?
KV uses the same keys, but deletes and lists are billed beyond 1 million a month on Workers Paid and limited to 1 000 a day on Free, so the answer carries a cost note. A lifecycle rule deletes by age, not by liveness, and would also expire the oldest entries of the live build, so the skill gives the folder cleanup instead.
Does it help Claude Sonnet?
In five of the 29 setups, yes. Without the skill Sonnet handled plain cleanups, custom roots, rollbacks and refusals to delete the live build, but it treated the live build as unknown when folders are named by deploymentId, kept cleaning around a no-build-id folder, and cleaned a bucket whose listing lacked the live id; it also copied three folder names wrong, once with an invisible character. With the skill it got 28, its one slip a dropped letter in a name. Haiku moved from 27 to 28.
OpenNext writes every deploy to a new folder in R2 and never removes the old ones. How we found the live build, what we deleted, and what a model got wrong.
Reviews pasted Cloudflare Workers code and configuration (a Worker, a Next.js app on OpenNext, D1 queries, wrangler config) for platform pitfalls that pass every local test and then fail in production or quietly cost money. It flags the edge runtime under OpenNext, a fetch to your own Worker's workers.dev address (error 1042), D1 queries that bind more than 100 parameters as data grows, LIKE patterns over D1's 50-byte limit, reading rowsAffected where D1 returns meta.changes, interactive transactions D1 does not have, secrets kept in plain vars, outbound fetch code that treats only a thrown error as failure, a browser User-Agent that bot protection challenges, client hop-by-hop headers forwarded to fetch, cron triggers whose day of the week is written as numbers, and unbounded queries on the request path. Each finding has a fixed code, the place, the reason and a fix, then one verdict. Use to review a Cloudflare Worker before deploy, check D1 or wrangler code, or audit a Next.js app running on Cloudflare.
Reviews pasted Next.js App Router code and config that runs on Cloudflare through OpenNext, for caching and ISR mistakes that serve a wrong or stale answer, or make every visit read the database. It flags an unstable_cache key whose cached shape changed while the key stayed, force-dynamic pages that disable the browser back-forward cache, a wildcard Cache-Control override that makes the whole site dynamic, a dynamic route that never starts ISR because generateStaticParams is missing, a static page reading D1 at build time, a writer that evicts a tag on every event, s-maxage trusted to cap database reads, whole pages cached instead of the data, a redirect added over a path that was cached as 404, a middleware matcher that skips robots.txt and sitemap files, and a clock stored inside cached data. Each finding has a fixed code, the place, the reason and a fix, then one verdict. Use to review Next.js caching, ISR and revalidation code, a next.config headers or redirects block, or middleware before deploying to Cloudflare.
Finds the loops behind a bill spike or an unexpected bill. Reviews a web app's code and config for loops and repeats that run up the bill on their own on Vercel, Turso, Cloudflare Workers and D1 and paid AI APIs. Finds two schedulers on one job, retries without a cap, work that triggers itself, client polling and React render loops, caches cleared on every write, middleware running on every static file, queues that resend failures forever, image settings that multiply transformations, health checks that count whole tables, alerts sent on every run and bots crawling endless filter URLs. Counts the runs per month, names the billed unit, ranks by cost and gives the change that stops each one. Use when asked why a Vercel, Turso or Cloudflare bill jumped, to find an infinite loop or a runaway cost, or to review a cron job, webhook, queue consumer, middleware or polling code before it ships.
Reviews pasted code and configuration that spends money (paid AI or API calls, purchases, paid lookups, anything billed per use) and checks whether the limit on that spending really stands in the way of the spending. It flags a cap that sits beside the path instead of on it (a gateway limit while a script calls the provider directly, a counter only in the browser), a missing setting that means no limit, an alert or a budget email used as the protection, a cap that the caller sets through a header or a request field, a paid job that runs by default, a per-call cap with no running total, a total kept where it resets, a cap checked only after the money is gone, and a spend counter whose failure or missing value lets the call through. Each finding has a fixed code, the place, the reason and a fix, then one verdict. Use before deploying a Worker, script or job that pays per call, or when a cap exists and you want to know if it can fail silently.