Ryan Dahl announced this morning that the entire Deno team is joining Cloudflare. Three sentences in that post set three different clocks. Deno Deploy keeps operating for six months and then shuts down. The runtime gets one year of monthly bug fixes and security updates, after which development ends, though the code stays open source. JSR, the registry, continues operating with its infrastructure moving to Cloudflare.
For anyone running a Deno application in production, the hosting target is gone by spring, the runtime stops moving by autumn, and the obvious migration destination is Cloudflare Workers. So we asked the question the announcement did not answer: if you move, can your dependencies come with you? We crawled every package JSR will list and counted what each one says about Workers.
TL;DR
- Deno Deploy shuts down in six months; the Deno runtime gets twelve months of fixes and then development ends; JSR survives on Cloudflare infrastructure.
- JSR listed 20,658 package names on 9 October 2026. Only 16,167 have a published version. Of those, 3,640 (22.5%) declare Cloudflare Workers support, 2,172 declare it explicitly unsupported, and 10,355 say nothing.
- Of the 9,520 packages that declare Deno support, the cohort most likely to be sitting in a Deno app right now, only 3,582 also declare Workers.
- Weighted by dependents, 2,407 of 7,944 dependency edges inside the Deno standard library point at packages that explicitly declare Workers unsupported, including
@std/fs(955 dependents) and@std/http(253). - All eight published
@freshpackages decline to claim Workers support. Five say explicitly that it is unsupported. - These are author-declared badges, not test results. JSR’s own documentation calls the default state “Unknown support”, meaning the author does not know.
What was actually announced
It is worth separating the three timelines, because teams tend to collapse them into one and then plan against the wrong deadline.
Deno Deploy: six months. A hosting product with a stated shutdown date, so everything on it needs a new home inside two quarters. That includes the parts people forget: cron triggers, KV, queues, environment configuration and whatever DNS points at it.
The runtime: twelve months of maintenance, then nothing. Monthly bug fixes and security updates for a year, then development ends. This is the softer deadline and the more dangerous one, because nothing breaks on the anniversary. The binary keeps working. What stops is the stream of security patches.
JSR: continues. The registry moves to Cloudflare infrastructure and keeps serving packages. That is genuinely good news for anyone with jsr: specifiers in a lockfile, and it is also the reason this post is a measurement rather than a panic. The packages will still be there. The question is whether they run where you are about to put them.
We wrote in August that Deno’s Celld gave architects a Durable Objects pattern without Cloudflare. That recommendation has a new expiry date attached to it, and we would rather say so than let it sit there.
What we measured
JSR exposes a public listing endpoint at api.jsr.io/packages. We paged through it on 9 October 2026 and collected 20,658 package records across 207 pages, at which point the listing ran out at ptt/zz. Every record carries a runtimeCompat object with one key per runtime JSR tracks: Deno, Node.js, Cloudflare Workers (the key is workerd), Bun and browsers. Each key can be true, false or absent.
We treated a package as published if it reported at least one version, which cut 4,491 empty names and leaves 16,167 as the denominator below. Where the picture needed weighting we pulled per-package dependent counts from the individual package endpoint.
The census
Here is what the 16,167 published packages declare, per runtime.
| Runtime | Supported | Unsupported | Unknown | % supported |
|---|---|---|---|---|
| Deno | 9,520 | 366 | 6,281 | 58.9% |
| Node.js | 7,195 | 1,370 | 7,602 | 44.5% |
| Bun | 5,999 | 1,394 | 8,774 | 37.1% |
| Browser | 5,327 | 2,476 | 8,364 | 32.9% |
| Cloudflare Workers | 3,640 | 2,172 | 10,355 | 22.5% |
Workers is last on the list by a wide margin. It is also the runtime with the largest unknown column: 10,355 packages, 64% of the registry, have never said one way or the other. A further 5,489 packages (34.0% of the published set) declare nothing for any runtime at all, so a third of JSR is silent on the whole question.
The obvious objection is that this is a long tail problem, that the 22.5% figure is dragged down by abandoned one-version experiments, and that anything actively maintained will have filled the field in. We checked. Of the 5,918 published packages updated at any point in 2026, 1,243 declare Workers support. That is 21.0%, slightly worse than the all-time figure. Waiting for the metadata to improve is not a strategy.
The cohort that actually matters
A registry-wide percentage is a weak proxy for your build. The sharper question is about the 9,520 packages that declare Deno support, because those are the ones plausibly sitting in a Deno project today. Within that cohort:
- 3,582 (37.6%) also declare Cloudflare Workers support.
- 1,798 declare Workers explicitly unsupported. These are not unknowns. The author looked at the question and answered no.
- 4,140 are unknown.
- 2,249 declare Deno supported and no other runtime supported at all.
So for a package you already trust to run on Deno, the majority answer is that it has not told you it runs on Workers, and in roughly one case in five it has told you it does not.
Weighting by dependents makes it worse
Counting packages equally flatters the result, because it gives an abandoned personal utility the same weight as the standard library. So we pulled dependent counts for the two scopes that matter most to a Deno codebase.
The standard library has 43 published packages. Thirty declare Workers support, nine declare it explicitly unsupported, and four are unknown. Those 43 packages carry 7,944 recorded dependency edges between them, and the split is not proportional to the package count:
| Workers declaration | Dependency edges into @std |
Share |
|---|---|---|
| Supported | 5,329 | 67.1% |
| Explicitly unsupported | 2,407 | 30.3% |
| Unknown | 208 | 2.6% |
Nearly a third of the standard library’s pull is into modules that have declared they do not work on the runtime you are migrating to. The individual offenders are exactly the ones you would guess, which is the point: they are the modules that touch the machine.
| Package | Dependents | Workers |
|---|---|---|
@std/path |
1,860 | Supported |
@std/fs |
955 | Unsupported |
@std/cli |
578 | Unsupported |
@std/http |
253 | Unsupported |
@std/dotenv |
177 | Unsupported |
@std/crypto |
156 | Unsupported |
@std/testing |
145 | Unsupported |
@std/log |
113 | Unsupported |
@std/net |
27 | Unsupported |
A filesystem module not working on a serverless runtime with no filesystem is not a scandal. What it is, is 955 dependency edges that each need a human decision.
Fresh declares zero
The announcement addressed the runtime, the hosting product and the registry. It did not mention Fresh, Deno’s web framework, which is the layer most Deno Deploy applications are actually written in.
There are eight published packages in the @fresh scope. None of them declares Cloudflare Workers support. Five declare it explicitly unsupported, including @fresh/core, which has 82 published versions and 50 recorded dependents. The remaining three are unknown. The @deno scope tells the same story: 27 published packages, exactly one declaring Workers support, with ten explicit refusals including deployctl, dnt and otel.
Frameworks built for the edge come out the other way round. All 29 published @hono packages either declare Workers support (26) or are silent (3), with zero refusals, and all three @oak packages declare support. If your Deno app is a Hono app, the migration is a deployment change. If it is a Fresh app, it is a rewrite, and nothing in the announcement tells you that.
These are claims, not test results
This changes what the numbers are good for. JSR’s documentation is explicit about where the field comes from: a package can declare a support level of “Supported”, “Unsupported”, or “Unknown support”, where “Unknown support means that the package author does not know if the package is compatible with the runtime”, and the value is edited by hand from the Settings tab on the package page.
Nothing runs. No CI job proves the claim. The 2,172 explicit refusals are reliable, because nobody marks their own package unsupported by accident, but the 3,640 declarations of support are an advertisement rather than a guarantee, and the 10,355 unknowns carry no information at all. That is exactly why they cannot be read as “probably fine”.
The operational lesson is one we keep relearning on client audits: a metadata field cannot prove behaviour. Registry badges are useful for ordering the testing work, not for skipping it.
The registry’s own books do not balance
Two smaller findings from the same crawl are worth logging. First, the listing endpoint reports a total of 22,507 packages while serving only 20,658 of them before the pages run dry. That is 1,849 names the registry counts but will not enumerate, so any inventory you build from the public listing is complete only against itself. Second, 5,394 of the 16,167 published packages (33.4%) have no linked source repository recorded. JSR verifies repository links, which is the right call, but the consequence is that a third of the registry offers you a tarball and no upstream. If a package stalls after the move, you have nowhere to open the issue.
What to do in the next six months
The useful version of this post is a work order, not a percentage.
- Inventory your specifiers, not your imports. Pull every
jsr:andnpm:specifier out of your lockfile, including transitives. The dependent counts above are a reminder that the risky modules arrive through other packages. - Resolve each against
runtimeCompatand sort into three piles. Explicit refusals are rewrites and need owners now. Declared support goes to the back of the queue. Unknowns go on a test list, which will be the longest of the three. - Test the unknowns in a Workers build, not locally. Node compatibility mode in Workers covers a lot of the 7,195 Node-declaring packages, which is the cheapest win available. Find out which ones it covers by running them.
- Treat the framework separately from the libraries. If you are on Fresh, the framework migration is the project and the dependency audit is a subtask. If you are on Hono or Oak, invert that.
- Put a date on the runtime, not just the host. The six-month clock gets attention because something switches off. Diary the twelve-month one too, with a named owner, because that is when your security patch stream quietly stops.
The pattern is not specific to Deno. We looked at five previous database acquisitions last week, and at exit tooling that lives on somebody else’s download page before that. The recurring failure is that the migration estimate gets made from the announcement blog post instead of from the dependency graph, and the announcement never mentions your dependencies.
REPTILEHAUS builds and migrates production JavaScript and TypeScript systems, and a fair amount of that work is auditing a dependency graph against a runtime it was never built for. If you have something on Deno Deploy and six months to get it off, get in touch and we will start with the lockfile.
Method: full crawl of the public api.jsr.io/packages listing on 9 October 2026 (20,658 records, 207 pages), filtered to the 16,167 packages with at least one published version. Dependent counts come from the individual package endpoint. Runtime support values are author-declared registry metadata, not test results.
📷 Photo by Taylor Vick on Unsplash


