What Happened
Web Infrastructure · Software Engineering · Information Security · Engineering BriefCutover of June 2026 · record to September 2026
Cloudflare moves cdnjs onto its own Developer Platform
9 Billion Requests a Day, Moved Without Rebuilding a File
On 23 June 2026 cdnjs, the free CDN behind about one website in nine, began running exclusively on Cloudflare’s Developer Platform; Cloudflare published the account on 30 July. The migration is the headline and the rollback is the lesson: an earlier attempt regenerated the old catalogue, every file came back with a different integrity hash, and for anyone who had pinned one that is not a difference but a blank page. So the catalogue was copied, byte for byte. Three weeks after the cutover, the same lesson arrived from the other side — the new publishing bot was found dropping the last byte of every file it extracted.
- 23 Jun 2026exclusive on the Developer Platform; disclosed 37 days later
- 9.18 bnrequests a day, averaged over the twelve months to July 2026 in cdnjs’s own monthly reports; July alone was 7.4 bn
- 98.6%cache hit rate, as Cloudflare states it — leaving roughly 126 million requests a day to go past the cache (our arithmetic)
- 1 bytecut from the end of every file the new publishing bot extracted, until a fix on 17 July 2026
| Standing | What is claimed |
|---|---|
| Documented | A browser handed integrity="sha384-…" hashes what it receives and, if nothing matches, 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. |
| Documented | Two platform limits were raised before the cutover, and Cloudflare’s changelog dates both. On 11 February 2026 the paid-plan subrequest limit went from 1,000 to a default of 10,000 per invocation, configurable up to 10 million. On 3 March 2026 Workflows went from 1,024 steps to 10,000, configurable to 25,000. |
| Documented | Three weeks after the cutover, a user reported Font Awesome 7.3.0 fonts from cdnjs that would not decode. The engineer running the migration traced it to the tar parser the new publishing bot uses, which stripped the last byte of every file entry; most files end in a newline and survived, but fonts, WebAssembly, SVG, minified CSS and JSON did not. Font Awesome 7.1.0 to 7.3.0 were fixed and republished on 17 July. |
| Documented | The GitHub repository that had been cdnjs’s source of truth received its last automated commit on 30 September 2025. On 3 September 2026 it gained a notice that it “is no longer updated as it became too large” and that cdnjs is now powered by an R2 bucket. |
| Documented in the project’s own reports | Traffic and reach. cdnjs’s monthly reports, built from data Cloudflare provides, put daily requests between 9.0 and 10.0 billion from June 2025 to April 2026, then 8.6, 8.5 and 7.4 billion in May, June and July 2026. W3Techs, which Cloudflare’s post itself links, measures cdnjs on 11.3% of all websites in September 2026 — 48.0% of the sites whose JavaScript CDN it can identify. |
| Confirmed by the operator, not verifiable here | The cutover date; 108,000 requests a second; 330+ data centres; a 98.6% cache hit rate; the new architecture. And an earlier migration attempt that was rolled back: re-processing old packages gave files that were correct but not byte-identical, so their integrity hashes changed, and the catalogue was then copied from KV to R2 as-is. |
| Asserted, and complicated by the project’s own records | 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. A pull request written during the pre-cutover comparison adds that both the old and the new hashing pipelines are “best-effort” and silently skip files they cannot hash. |
Timeline
How it got here fifteen years, one step that cannot be dated, and what came after the post
- 2011Created, then moved to Cloudflare. Ryan Kirkman and Thomas Davis start CDNJS early in the year on Amazon CloudFront; cost and the lack of easy HTTPS push them off it, and in June it goes live on Cloudflare, free of charge.
- Late 2019Cloudflare takes over maintenance of the repository after a community bot stopped working. The repository then holds 182 GB without its history.
- Apr 2020The origin goes dark. A core data centre housing the primary cdnjs origin is offline for about four hours; Cloudflare’s cache limits the damage to uncached files. Cloudflare later calls it the first wake-up call.
- Sep 2020Serving moves; publishing does not. Files are served from Workers and KV and pre-compressed with Brotli and gzip. The pipeline that watches npm and GitHub stays on Google Cloud.
- Apr – Jun 2021The publishing bot is broken into, by a researcher. A crafted npm package lets RyotaK run code on the auto-update server. Cloudflare revokes every credential within the hour, ships a fix within a day and finishes redesigning the pipeline on 3 June; it says no existing library was modified.
- 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. No source gives it a date.
- 30 Sep 2025The GitHub mirror stops. The last automated commit lands in the repository that had been cdnjs’s source of truth.
- 11 Feb 2026Subrequests. The paid-plan default rises from 1,000 to 10,000 per invocation, configurable to 10 million.
- 3 Mar 2026Workflow steps. 1,024 becomes 10,000 by default, configurable to 25,000.
- 11 – 17 Jun 2026A shadow comparison before the switch. The new metadata worker is set to check its answers against the legacy origin on a sample of live traffic, with a rule that more hashes than before counts as gained coverage and fewer as lost.
- 23 Jun 2026cdnjs runs exclusively on the Developer Platform. R2 becomes the single source of truth for file content; KV keeps only metadata.
- 13 – 17 Jul 2026The missing byte. Broken Font Awesome fonts are reported, traced to the new bot’s tar parser, fixed and republished within four days.
- 30 Jul 2026Cloudflare publishes the account, 37 days after the cutover. InfoQ reports it on 14 August.
- 25 – 29 Aug 2026Mirrors and the website. The first mirror operators receive read-only access to the R2 catalogue on 25 August; on 29 August cdnjs.com is switched to the Worker that already served the API.
- 3 Sep 2026The GitHub repository says so. A notice is added: no longer updated, too large, powered by R2.
One step has no date, and it is the important one
Everything else here is dated at least to the month. 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 date on which automatic updates were paused around the cutover is not in the record either; only that they were re-enabled before 13 July.
The Argument
What Cloudflare is arguing dogfooding, and the sentence it is all pointing at
The post’s own word 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 — “it can probably run whatever you’re building.” The two halves deserve separating. The evidence is real: two platform limits were raised because cdnjs hit them, Cloudflare’s changelog dates both to February and March 2026, and they apply to every paying customer. It is also smaller than the post makes it sound. The post, and InfoQ after it, say subrequests “now go up to 10 million”; the changelog says the paid default became 10,000, with 10 million as a ceiling a customer must set. That is a tenfold rise by default, not ten-thousandfold. The inference is a sales pitch, and the post does not pretend otherwise. It is explicit that this was not a performance problem — “We didn’t migrate because cdnjs was slow” — and credits the old architecture with a 98% cache hit rate and, in its words, no outages. The complaint was that changing anything meant coordinating deployments across Google Cloud functions, a virtual machine and Cloudflare, and that a partial failure was invisible: a version could reach KV, silently miss the GitHub repository, and serve fine for weeks until somebody noticed the two stores had diverged.
- 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×the rise in the default Workers subrequest limit, from 1,000 to 10,000 — with a configurable ceiling of 10 million, which is where the post’s headline figure comes from.
What Others Add
The mechanism, from both sides why a regenerated file is a blank page, and a missing byte is too
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. Across origins the check also needs CORS.
- Source: MDN. This is the whole reason the first migration attempt had to be undone.
- A page can pin a hash:
Determinism
Rebuilding gives correct bytes, not the same bytes
- Minifiers and compressors are not fully deterministic across versions, so re-running them 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.
The missing byte
The same lesson, arriving from the other side
- In the maintainers’ own tracker, the engineer running the migration wrote that the new bot’s tar parser “strips the last byte of every file entry” — harmless where that byte is a newline, fatal in a font.
- The fix meant republishing Font Awesome 7.1.0 to 7.3.0 under their existing version addresses.
- Our reading: that is the one thing the rollback says must not happen to a file in the wild, done because the file was wrong. The rollback and the byte are one lesson from both sides — the bytes a CDN first publishes are the ones it has to live with.
What is still unknown
How many stored hashes are wrong, and how many were never made
- Cloudflare says it is still working on making the stored hashes match reality, “due to bugs in the old system”.
- A June 2026 pull request adds that both hashing pipelines skip files they cannot hash, and counts a new pipeline that returns more hashes as gained coverage.
- No scale is given for either. A wrong stored hash on a file somebody pinned is a broken page somewhere.
Around the migration the security record, the figures, and what the project did next
The publishing pipeline is the part worth securing, and there is a precedent. The post says retiring the old pipeline removed a pile of things to secure — functions, a virtual machine, buckets, service-account keys. In April 2021 the researcher RyotaK showed why that surface matters: an npm package carrying a crafted symbolic link made the auto-update server run his code and leak its credentials. Cloudflare revoked them within the hour, took the service offline, and finished redesigning the pipeline that June; it says no existing library was altered. That was fixed five years ago and is not one of the unnamed vulnerabilities the 2026 post mentions. The figures hold up as a year’s averages, and less well month by month. The post’s reach figures are W3Techs’, which the post links: 11.3% of all websites in September 2026, against the post’s “roughly 12%”. Its “9 billion per day” matches cdnjs’s own monthly reports as a year’s average — 9.18 billion over the twelve months to July 2026 — but July itself was 7.4 billion, the lowest month of the fourteen read. No source gives a reason, and none is offered here. After the post, the migration kept going. Mirror operators, among them a mirror serving mainland China and an integrity-monitoring service, received read-only access to the R2 catalogue from 25 August; the cdnjs.com website moved onto the API’s Worker on 29 August; and the GitHub repository now says plainly that it is no longer updated.
- 7.4 bnrequests a day in July 2026, against a twelve-month average of 9.18 bn — no source says why.
- 11.3%of all websites use cdnjs, W3Techs, September 2026 — which puts a JavaScript CDN on about 23.5% of the web (our arithmetic).
| Old | New | What actually changed |
|---|---|---|
| Workers KV + a GitHub repository | R2 as the single source of truth | Neither store was authoritative before, and when they drifted there was no clean way to reconcile them. The GitHub copy had in fact stopped receiving files almost nine months before the cutover. Mirrors now sync from R2 over its S3 interface, with read-only credentials issued on request. |
| 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. |
| A bare-metal origin behind the edge | cache → R2 → DigitalOcean Spaces | DigitalOcean mirrors the storage: architecturally a disaster-recovery copy, operationally a live fallback. As of the post, a Cloudflare-hosted origin still sat in the chain until the GitHub backfill lands; no later source says whether it has. |
| A separate static website | The same Worker as the API | On 29 August 2026 cdnjs.com was switched to pages rendered by the Worker that serves the API — one more piece moved onto the same platform, after the post. |
Conclusion
What to take from it one transferable lesson, and what to hold loosely
Copy the bytes; do not rebuild them — and get them right the first time
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 it by trying and rolling back, and published the fact. The missing byte of July is the same rule seen from the other side: a file published wrong can only be put right by breaking the promise that it never changes.
Complete in the headline’s sense, still moving in practice
cdnjs does run on the Developer Platform. Around that fact the record shows a paused and re-enabled update pipeline, a defect found and fixed three weeks in, a website moved two months later, mirrors switched to R2, and an origin the post said would retire once a backfill landed. None of it undoes the headline; all of it is what a migration of this size actually looks like.
Hold the figures loosely, and the security claim loosest of all
“9 billion a day” is fair as a year’s average and generous for the month the post appeared in; the limit raise is tenfold by default and ten-thousandfold only for a customer who asks. Those are the solid parts. The sentence to hold loosest is that retiring the old pipeline “closed all of the recently opened cdnjs vulnerabilities” — no count, no identifier, no severity, in a post otherwise precise to the digit.
What could not be verified
Unconfirmed report — Cloudflare, in its own account: that retiring the old pipeline “closed all of the recently opened cdnjs vulnerabilities”. No count, identifier or date is given, and no security advisory is published in the project’s main repositories.
Unconfirmed report — Cloudflare: that the GitHub repository passed 1.1 TB of packed storage and that GitHub’s archive service refused to build downloads for it. GitHub’s own repository record gives a size of roughly 70 GB, on a measure it does not define; nothing reconciles the two.
Unconfirmed report — Cloudflare: that the architecture used from 2020 to 2026 had no outages. No incident record for cdnjs specifically was found either way.
Unconfirmed report — Cloudflare: that language models reach for cdnjs because their training data is full of it. It is offered as explanation, not measured.
Take-home and sources
- Simona Badoiu, “Dogfooding at scale: migrating cdnjs to Cloudflare’s Developer Platform”, The Cloudflare Blog, 30 Jul 2026
- W3Techs, “Usage statistics and market share of CDNJS for websites”, September 2026
- Cloudflare Changelog, “Workers are no longer limited to 1000 subrequests”, 11 Feb 2026, and “Workflows step limit increased to 25,000 steps per instance”, 3 Mar 2026
- Matthew Prince, “CDNJS: Community Moderated Javascript Libraries + CloudFlare”, 16 Jun 2011
- Zack Bloom, “An Update on CDNJS”, 19 Dec 2019
- Tyler Caslin, “Migrating cdnjs to serverless with Workers KV”, 10 Sep 2020
- Jonathan Ganz, Thomas Calderon and Sven Sauleau, “Cloudflare’s Handling of an RCE Vulnerability in cdnjs”, 24 Jul 2021 — all The Cloudflare Blog
- RyotaK, “Remote code execution in cdnjs of Cloudflare”, 16 Jul 2021
- MDN Web Docs, “Subresource Integrity”, Mozilla
- Leela Kumili, “Cloudflare Migrates JavaScript CDN Serving 9B Requests a Day to Its Developer Platform”, InfoQ, 14 Aug 2026
- cdnjs on GitHub: monthly usage reports (cf-stats), June 2025 to July 2026
- metadata-worker pull requests 6 and 7, June 2026
- cdnjs issues 14305, 14307 and 14309, July–August 2026
- api-server pull request 279, 29 Aug 2026
- the cdnjs/cdnjs repository README and its GitHub repository record, September 2026. All sources read in full, 28 Sep 2026.
Reliable
Worth believing
Sharing a subject
- The Claude Code Quality Postmortem — Three Unrelated ChangesSoftware Engineering
- AI Reasoning Traces: Encrypted, Not HiddenInformation Security
- The Harness Ships, the Governance Doesn’tSoftware Engineering
- 533 Bytes an Entry, 100 Terabytes a FleetSoftware Engineering
- OpenAI Cuts Off Cursor: What Stops, and What Doesn'tSoftware Engineering
- Sophistication Stopped Telling You WhoInformation Security
Sharing a source domain
- The Claude Code Quality Postmortem — Three Unrelated Changesgithub.com · infoq.com
- Local LLMs and Buying a Mac — A Technical Reportgithub.com
- Grok Build Shipped Whole Repos to xAI's Cloudgithub.com
- Avalanche's RWA Boom, and Why AVAX Still Fallsgithub.com
- A Retreat Executed as a Pivot — BAT Roadmap 4.0 and the Buyback With No Numbercloudflare.com
- Five Names for One Stack, and No Agreed Ordergithub.com
- Enough, or Less? Context Engineering Said Both in One Weekgithub.com
- It Began as Tuning an Agent. By March It Meant Everything but the Model.github.com
- One Term, Coined Twice, Two Weeks Apart. The Joke Won.github.com
- Dorado v4 to v6 — What Changed, How Much, and Whether It Was Goodgithub.com
- 533 Bytes an Entry, 100 Terabytes a Fleetcloudflare.com
- Shunting Bulk Reads to a Cheaper Model — What the 90% Actually Cutsgithub.com