What Happened
Web Infrastructure · Software Engineering · Information Security · Engineering BriefTratopedia · 16 Aug 2026
Cloudflare moves cdnjs onto its own Developer Platform
9 Billion Requests a Day, Moved Without Rebuilding a File
On 23 June 2026 cdnjs began running exclusively on Cloudflare's Developer Platform, and on 30 July Cloudflare published the account. The migration is the headline; the rollback is the lesson. An earlier attempt re-processed the old catalogue and had to be abandoned, because minifiers are not deterministic across versions and every regenerated file came out with a different integrity hash — which, for anyone who had pinned one, is not a difference but a blank page.
- 23 Jun 2026exclusive on the Developer Platform; disclosed 37 days later
- 108,000/srequests, about 9 billion a day
- 98.6%cache hit rate — leaving ~126 million requests a day to go past it
- 1.1 TBthe git mirror GitHub could no longer make downloads for
| Standing | What is claimed |
|---|---|
| Documented | A browser handed integrity="sha384-…" hashes what it receives and, on a mismatch, refuses to load the resource and returns a network error. There is no degraded mode. This is why a regenerated file is a serving break rather than a cosmetic difference. |
| Confirmed by the operator, not verifiable here | The cutover date; 108,000 requests a second and 9 billion a day; 330+ data centres; a 98.6% cache hit rate; use on roughly 12% of all websites and 48.3% of the JavaScript CDN market. Every one of these is Cloudflare reporting on Cloudflare, with no methodology and no attribution. |
| Confirmed, and unusually candid | An earlier migration attempt was rolled back. Re-processing the old packages produced files that were correct but not byte-identical, so their integrity hashes changed. The catalogue was then copied from KV to R2 as-is instead. |
| Asserted, unquantified | Retiring the old pipeline “closed all of the recently opened cdnjs vulnerabilities”. No count, no identifiers, no severities, no dates — in a post that is otherwise specific to the digit. |
| Asserted, and undercut in the same post | Every file on cdnjs carries an SRI hash — stated three sentences before the admission that Cloudflare is still working on ensuring the stored hashes match reality, because of bugs in the old system. Both sentences are in the post; carrying one without the other misreports it. |
Timeline
How it got here fifteen years, and one step that cannot be dated
- 2011Built as a community mirror. Ryan Kirkman and Thomas Davis start cdnjs when npm is barely a year old and “just drop a <script> tag” is how the web ships JavaScript. Cloudflare begins hosting it free of charge months later.
- 2019Cloudflare takes over maintenance of the project, not just its hosting.
- 2020Serving moves; publishing does not. Files begin being served from Workers and KV with a bare-metal origin behind them, and every asset is pre-compressed with Brotli and gzip. The pipeline that watches npm and GitHub stays on Google Cloud, because Workflows, Queues, Durable Objects, R2 and Containers do not exist yet.
- UndatedThe attempt that was rolled back. Old packages are re-processed and written straight to R2; the results do not byte-match what KV had been serving, so the integrity hashes differ and the change is reversed. The post gives this no date at all, which is why it sits here rather than in sequence — and it is the most instructive thing in the piece.
- Before Jun 2026Two platform ceilings are raised rather than worked around. Workers subrequests go from 1,000 to 10 million per invocation on paid plans; Workflow steps from 1,024 to 10,000, configurable to 25,000.
- 23 Jun 2026cdnjs runs exclusively on the Developer Platform. R2 becomes the single source of truth for file content; KV keeps only metadata.
- 30 Jul 2026The account is published, 37 days after the cutover.
One step has no date, and it is the important one
Everything else here is dated to the day. The rolled-back attempt is not dated at all — not a month, not a year — so it cannot honestly be placed in sequence. It is listed as undated rather than guessed at.
The Argument
What Cloudflare is arguing dogfooding, and the sentence it is all pointing at
The post's own word for this is dogfooding, and its argument is a syllogism: cdnjs is enormous, cdnjs now runs on the same building blocks anyone can rent, therefore those building blocks will hold whatever you are building. The closing sentence says exactly that — “it can probably run whatever you're building.” It is worth separating the two halves. The evidence is real: two platform ceilings were raised because cdnjs hit them, and those raises apply to every paying customer, not to cdnjs alone. The inference is a sales pitch, and the post is not pretending otherwise. What is notable is that Cloudflare is also explicit that this was not a performance problem. “We didn't migrate because cdnjs was slow. We migrated because we want to keep improving it.” The old architecture is credited with a 98% cache hit rate, billions of requests and no outages. The complaint was that changing anything meant coordinating deployments across GCP Functions, a VM and Cloudflare — and that when something half-failed, nothing in the system knew. A version could write to KV, silently fail to reach the GitHub repo, and serve fine for weeks until a human noticed the two stores had diverged. There was no alert for it, and the post is clear about why there could not be: no component knew the whole pipeline's state.
- 26Cloud Functions to check npm — one per letter of the alphabet, each with its own deployment and its own logs.
- 274hand-curated
.gitignoreentries blocking broken or oddly-versioned releases — the post's own phrase is “a documented graveyard”. - 10,000×the increase in the Workers subrequest ceiling, from 1,000 to 10 million — a platform change, not a cdnjs one.
What Others Add
The mechanism the post assumes you know why a regenerated file is a blank page, not a difference
Subresource Integrity
The browser refuses, it does not degrade
- A page can pin a hash:
<script integrity="sha384-…">. - The browser hashes what arrives and compares. On a mismatch it returns a network error and the script never runs.
- Source: MDN. This is the whole reason the first migration attempt had to be undone.
- A page can pin a hash:
Determinism
Minifier output is not stable across versions
- Re-running the same tools on the same input a few years later gives correct output that is not identical output.
- Different bytes mean a different hash, and a different hash means every page that pinned the old one breaks.
- The general lesson: a content-addressed store cannot be rebuilt. It can only be copied.
What is still unknown
How many stored hashes are currently wrong
- Cloudflare says it is still working on making the stored hashes match reality, “due to bugs in the old system”.
- No scale is given. A wrong stored hash on a file somebody pinned is a broken page somewhere.
- This is the single most consequential unknown on this page.
| Old | New | What actually changed |
|---|---|---|
| Workers KV + a GitHub repo | R2 as the single source of truth | Neither store was authoritative before, and when they drifted there was no clean way to reconcile them. R2 also has no practical size limit, so source maps and font packs that would not fit in KV now sit with everything else. |
| A chain of Cloud Functions triggered by bucket events | Workflows, with Queues and a Durable Object counter | Storage had been doing double duty as a message queue — no dead-letter queue, no backlog visibility, no clean replay. Workflows keep each step's state, so a timeout resumes rather than restarts. |
| Two logging systems with no common key | One platform, one trace | The failure this was meant to catch is not an outage but a partial success: a version that wrote to one store, silently missed the other, and served fine for weeks. |
| A bare-metal origin behind the edge | cache → R2 → DigitalOcean Spaces | DigitalOcean had sponsored the cdnjs website for years and now mirrors the storage: architecturally a disaster-recovery copy, operationally a live fallback. A Cloudflare-hosted origin still sits in the chain until the GitHub backfill lands. |
Conclusion
What to take from it one transferable lesson, and three things to hold loosely
Copy the bytes; do not rebuild them
This is the part that transfers to systems that have nothing to do with CDNs. If anyone downstream has pinned a hash of your output, that output is no longer something you can regenerate — the toolchain will have moved, the bytes will differ, and correct will not be good enough. Cloudflare learned this by trying it and rolling back, and published the fact.
Complete in the headline's sense, unfinished in one stated respect
cdnjs does run on the Developer Platform. A Cloudflare-hosted origin also remains in the serving chain until the GitHub backfill lands in R2. The post says so itself, and an article that sanded that off would be reporting the headline rather than the piece.
Hold the figures loosely, and the security claim loosest of all
Every operational number here is Cloudflare reporting on Cloudflare, with no methodology and no attribution — that is the ordinary status of an engineering blog post, not a scandal. But “closed all of the recently opened cdnjs vulnerabilities” carries no count, no identifier and no severity, in a piece that is otherwise precise to the digit. Take the 10,000× subrequest raise as the solid evidence; take that sentence as the weakest thing in the post.