Skip to content

✍️ 필사 모드: Deno 2 and 3 Deep Dive 2026 — The Node-Compatibility Era, JSR, Fresh 2, and Deno KV (Where the Runtime Bet Went) english

English
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

Prologue — Ryan Dahl's Second Self-Negation

Ryan Dahl built Node in 2009. In 2018 at JSConf EU, he gave the famous "10 Things I Regret About Node.js" talk. Then he built Deno. Default-deny security, TS first-class, URL imports, no package.json — every choice was an explicit answer to Node.

Then in September 2024, Deno 2 shipped. The biggest change is self-negation.

  • package.json support — first-class.
  • node_modules directory support — optional, but available.
  • npm registry imports — via npm:/jsr: specifiers.
  • deno install as an npm-compatible package manager.
  • Workspace (monorepo) support.

Deno accepted, six years later, almost every Node design decision it had initially rejected. Pride swallowed.

Is this a retreat or an evolution? Both. A shift from idealism to pragmatism, and at the same time, a bet that acknowledges the reality of the JS ecosystem (npm is not going away).

This essay summarizes where Deno's bet has landed about 20 months after the Deno 2 launch — mid-2026 — how the three-way battle with Bun and Node 22+ settled, and where the security model, JSR, Fresh 2, and Deno KV actually sit in the real world.


Chapter 1 · The Heart of Deno 2 — Node Compatibility Becomes the Default

The Deno 1 worldview, and its limits

Deno 1 tried to draw a pure world.

  • URL imports — import { foo } from "https://deno.land/std/...";
  • Explicit permissions — deno run --allow-net=api.example.com server.ts
  • TypeScript first-class — run .ts with zero config.
  • No node_modules, no package.json.

The problem was simple. 90 percent of the JS world already lives on npm. Express, React, Prisma, AWS SDK, Sentry, Stripe SDK — all npm. Deno added the npm: specifier early as a compat shim, but getting to real production fell short. The package.json already in the repo couldn't be read directly, full-stack tools that touched node_modules broke, monorepo workflows felt awkward.

Deno 2's answer was clear. "It also runs the way Node ran."

What changed (September 2024)

# Deno 2 — from an existing Node project
deno install            # reads package.json, creates node_modules
deno run npm:express    # runs an npm package directly
deno task dev           # runs scripts.dev from package.json
AreaDeno 1Deno 2
package.jsonignored / partialfirst-class — deno install reads it
node_modulesdeliberately absentoptional — nodeModulesDir: auto
npm packagesnpm: specifiersame, plus automatic from package.json
deno installURL-based binary installNode-compatible package manager
deno run npm:foopartialstable, broad compat
workspacenonefirst-class — workspace field in deno.json

Deno 2's motto is no longer "replace Node." It is "shrink the friction between Node and Deno to near zero."

Has migration become easy?

Trying to take an existing Node project and run it on Deno:

  • Small Express API — often runs in 5 minutes. deno run --allow-net --allow-read npm:tsx server.ts.
  • Next.js — works. Caveat: next dev/next build often shells out to Node directly, which dilutes the meaning of the permission model.
  • Prisma plus Postgres — works. Small friction around native binary compat possible.
  • AWS SDK v3 — nearly drop-in.

The friction-heavy area for the first year was native addons (sharp, canvas, bcrypt-native, anything with C++ bindings), and N-API compatibility improved steadily through 2025. By mid-2026, more than 90 percent of typical npm packages run on Deno 2 without issue.


Chapter 2 · deno install — The npm-Compatible Package Manager

Two modes

deno install runs in two modes.

# Global binary install (since Deno 1)
deno install -gA --name lint jsr:@std/cli/parser

# Project dependency install (new in Deno 2)
deno install            # reads package.json, creates node_modules
deno install --add npm:express@4   # add a new dependency
deno install --add jsr:@hono/hono  # add a JSR dependency

The second mode is the paradigm shift. It is now a command that can directly replace npm install, pnpm install, yarn install.

Speed and lockfile

hot cache, ~500 deps:
  npm install:    14s
  pnpm install:    4s
  bun install:     1.3s
  deno install:    2.1s

Not as fast as bun install, but faster than pnpm install and much faster than npm install. The lockfile is deno.lock (text JSON), and was diff-friendly from day one. A contrast with Bun's brief misstep on a binary lockfile.

node_modules mode

// deno.json
{
  "nodeModulesDir": "auto",   // or "manual" or false
  "lock": true
}

With auto, it reads package.json and creates node_modules automatically. With manual, it uses an existing node_modules populated by npm/pnpm/yarn (useful for large monorepo migrations). With false, only the Deno-1-style global cache is used.

The mere existence of this option is evidence that idealism was set aside in favor of pragmatism.


Chapter 3 · deno run for npm Packages Directly

Evolution of the npm: specifier

One of Deno 2's mottos: "import npm packages with no extra setup."

// app.ts
import express from "npm:express@4";
import { z } from "npm:zod";
import OpenAI from "npm:openai";

const app = express();
app.get("/", (_, res) => res.json({ ok: true }));
app.listen(3000);
deno run --allow-net --allow-read --allow-env app.ts

This just runs. No package.json needed, no node_modules needed (pulled into the global cache). Compared with Bun and Node which require package.json to start a project, single-file scripts are smoothest on Deno.

Compare with Bun and Node

# Single-file script with an npm dependency

# Deno
deno run --allow-net script.ts

# Bun
bun script.ts            # requires bun add first, or an inline shebang trick

# Node
npm init -y && npm i express && node script.js

In the quick-script-plus-one-or-two-npm-deps space, Deno still has the best dev UX. A Deno 1 strength that survived into Deno 2.


Chapter 4 · JSR — The JavaScript Registry Bet

Why another registry

JSR (jsr.io) is a new JavaScript registry the Deno team launched in early 2024. With npm already there, why another?

JSR's thesis:

  1. TS-native publishing — publish TS source directly. Consumers pick their own build tooling. (npm typically ships compiled JS plus .d.ts.)
  2. Standard ESM only — no CJS, none of the package.json maze.
  3. Runtime-agnostic — importable from Deno, Node, Bun, browsers.
  4. Quality score — a score showing documentation, tests, and type completeness.
  5. Scopes as first-class@scope/package as the model.

Usage examples

// just import
import { parse } from "jsr:@std/cli/parser";
import { Hono } from "jsr:@hono/hono";
# package.json style
deno install --add jsr:@hono/hono
# Also usable from Node
npx jsr add @hono/hono
# or directly — receives a built form

Adoption reality — mid-2026

CategoryJSR adoption
Deno first-party @std libraries100 percent — the new home for @std
Deno-ecosystem toolingbroad — Hono, Fresh, Oak, etc.
General JS librariesslow — many publish to npm in parallel
User basesmall slice of npm — but growing fast

JSR is not "kill npm" — it is "create a TS-first alternative." And it has partly succeeded: standard inside the Deno ecosystem, niche outside.

What JSR changed

  • TS library authors can defer build-tool choice to the consumer. Real simplification.
  • A way around npm's exports maze (CJS/ESM/types path mapping).
  • A first serious attempt at standardizing package quality (semver, types, docs combined into a score).

The npm side's reaction

A curious detail. In 2024 Deno also produced a BSD-licensed fork of the npm CLI — not named "npm" but a different name (to honor community guidelines). It triggered a small license/naming debate, but there was no major legal response from npm Inc. The message ended up being "npm compatibility comes first, antagonism second."


Chapter 5 · Fresh 2 — Islands Architecture, Round Two

Fresh 1's promise

Fresh was Deno's official full-stack framework. Core ideas:

  • No build step — SSR runs straight in dev.
  • Islands architecture — only parts of the page hydrate (client JS), the rest stays static HTML.
  • JSX with Preact — Preact, not React, optimizing for weight.
  • Deno-native — routing and handlers built around Deno's Request/Response standards.

A great bet, but the 1.x era hit limits with the routing model (file-based plus handler separation) and the absence of React-ecosystem compatibility that constrained adoption.

What Fresh 2 changed

// routes/api/hello.ts (Fresh 2 style)
import { define } from "$fresh/server.ts";

export const handler = define.handlers({
  async GET(ctx) {
    return new Response(JSON.stringify({ msg: "hello" }), {
      headers: { "content-type": "application/json" },
    });
  },
});
// routes/index.tsx
import { define } from "$fresh/server.ts";
import Counter from "../islands/Counter.tsx";

export default define.page<{ now: string }>((props) => (
  <main>
    <h1>Current time: {props.data.now}</h1>
    <Counter start={0} />
  </main>
));

Notable changes in Fresh 2:

  • Better type inferencedefine automatically propagates handler and page data types.
  • Server-components-like patterns — async components, page-level data fetch.
  • Better island detection — only components in the islands/ directory hydrate.
  • Tailwind integration improved — Tailwind in dev with no build step.
  • deno deploy integration — one-line deploy to Deno Deploy.

Why Fresh did not catch up in adoption (honestly)

  • Next.js has too much weight. If you start a full-stack project, 90 percent choose Next.js.
  • Preact as the choice creates friction with parts of the React ecosystem (some Form/Data/Animation libraries).
  • No-runtime portability — awkward when you want to run on Vercel or Cloudflare directly.

Fresh 2 is a strong choice for full-stack tied to Deno Deploy. But its path to becoming the full-stack default is narrow.


Chapter 6 · Deno KV — The Built-In KV Goes Production-Ready

What Deno KV is

Deno KV is a key-value store built into the Deno runtime. A single-node mode similar to SQLite, plus globally distributed mode in the Deno Deploy environment.

// kv.ts
const kv = await Deno.openKv();

// set
await kv.set(["users", "alice"], { name: "Alice", joined: Date.now() });

// get
const result = await kv.get<{ name: string }>(["users", "alice"]);
console.log(result.value?.name);  // "Alice"

// list (prefix query)
for await (const entry of kv.list({ prefix: ["users"] })) {
  console.log(entry.key, entry.value);
}

// atomic transaction
await kv.atomic()
  .check({ key: ["counter"], versionstamp: null })
  .set(["counter"], 1)
  .commit();

Status in 2026

AspectStatus
Local (SQLite-backed)GA (production-ready)
Deno Deploy (FoundationDB-backed, global)GA
Cross-region replicationautomatic
Atomic transactionssupported
Queue APIsupported (kv.enqueue)
Watch APIsupported — real-time subscriptions
Limitsper-key 64KB value, some plan limits

Deno KV targeted the Cloudflare KV and Workers KV space, but since it is tied to the Deno ecosystem, positioning is tighter. Even so, the slogan "a distributed KV you can start with one line" actually holds up.

Where it fits well

  • Session store — server-side sessions instead of JWT.
  • Feature flags — small read-heavy data that benefits from global distribution.
  • Queues and work distribution — kv.enqueue plus workers.
  • Cache — short-TTL response cache.

Where it is weak

  • Not a fit for a primary relational DB role — schema, joins, broader transactions.
  • Hard to access from outside services (must go through a Deno runtime).
  • Large values belong elsewhere; keep KV for metadata.

Chapter 7 · Workspace — Deno's Monorepo Answer

Monorepos become first-class

Deno 2 added the workspace field in deno.json.

// root deno.json
{
  "workspace": [
    "./packages/api",
    "./packages/web",
    "./packages/shared"
  ],
  "tasks": {
    "dev": "deno task --filter=* dev"
  }
}
// packages/api/deno.json
{
  "name": "@app/api",
  "version": "0.1.0",
  "exports": "./mod.ts",
  "tasks": {
    "dev": "deno run --watch --allow-net mod.ts"
  }
}

Internal packages import via import { foo } from "@app/shared". Nearly the same model as pnpm or Bun workspace, but install time is very short thanks to Deno's unified lockfile and cache.

Compared to Turborepo and Nx

ToolStrengthsWeaknesses
Deno workspacezero-config, lockfile-unified, fast installtask orchestration is simple
pnpm workspacebroad compat, familiar to everyoneinstall slower than Deno
Turborepobuild caching, strong graphconfiguration weight
Nxpowerful generators, big-monorepo standardsteep learning curve

Deno workspace shines in small to medium monorepos. Large monorepos where build-graph caching is essential still favor Turborepo or Nx.


Chapter 8 · Security Model — Still the Killer Feature

The differentiator that has survived from the very beginning. Default deny.

Permission flags at a glance

deno run script.ts                    # can do almost nothing
deno run --allow-read script.ts       # file reads
deno run --allow-net script.ts        # network
deno run --allow-env script.ts        # env vars
deno run --allow-write=./data script.ts   # write only this directory

# Deno 2 and later: finer scoping
deno run --allow-net=api.example.com,db.internal:5432 script.ts
deno run --allow-env=DATABASE_URL,REDIS_URL script.ts

What it really means in operations

Upsides:

  • Even if a dependency carries malicious code, you can contain it (supply-chain attack defense).
  • Production container privileges narrow once at the OS layer and again at the runtime layer.
  • Excellent as an AI-agent sandbox runtime — the code generated by a model has explicit, bounded capabilities.

Friction:

  • The first week, you guess permissions every time.
  • Many people just set --allow-all (or -A) and move on. Then the value is zero.
  • Different permissions in dev vs production can complicate configuration.

Deno 2 security improvements

  • More precise CIDR and domain scoping on --allow-net.
  • New --deny-net style explicit deny flags — narrow a broad allow.
  • Production-mode guidance — automatically narrower permissions in Deno Deploy.
  • Audit and trace — logging which permissions were actually used.

The security model gained value in 2025 and 2026 as software supply-chain attacks rose. After the xz-utils incident and the npm event-stream incident, more companies took the "default deny" stance seriously.


Chapter 9 · Where Is Deno 3?

Status in mid-2026

Deno 3 is not yet officially released (as of May 2026). The roadmap and RFC discussions point in these directions.

  • Stronger WinterCG 1.0 compliance — fetch, Streams, Response aligned to the standard.
  • A rethink of the default of TypeScript type-check — type check was the default through Deno 2, but conversations exist about turning it off by default due to weight.
  • The last gaps in Node API compatibilitycluster, dgram, parts of inspector.
  • Deeper JSR integration — make metadata like scores and security advisories usable from the CLI.
  • Evolution of Deno Deploy's isolate-per-region model — direct competition with Cloudflare Workers.

Whether the next big bet shows up or whether it remains incremental is not yet decided. Since Deno 2 was a large self-negation, Deno 3 is more likely to be a conservative evolution.


Chapter 10 · Deno vs Bun vs Node 22+ — Settling the Three-Way Battle

Positions in mid-2026

AxisNode 22+BunDeno 2
Adoption1st (dominant)2nd (dev-tooling focus)3rd (specific niches)
Cold start35-60ms10-20ms25-40ms
Node compat100 percent (itself)90-95 percent90-95 percent (since Deno 2)
TS native--experimental-strip-typeszero-configzero-config
Security modelstandard (all allowed)standarddefault-deny
Std librarylarge coresmallrich @std
Package managernpm/pnpm/yarnbun installdeno install
Registrynpm onlynpm onlynpm plus JSR
Full-stack frameworkNext/Astro/Remix(whatever runs on Node)Fresh 2
Built-in KVnonebun:sqliteDeno KV
Edge deployVercel/NetlifyCloudflare Workers is separate isolateDeno Deploy
AI agent sandboxpossible (manual)possibleexcellent fit (permissions)

Decision guide

Where Deno 2 fits:

  1. AI agent sandbox — running model-generated code with bounded permissions. Deno is clearly first here.
  2. High-security / government / parts of finance — the permission model becomes meaningful in audit trails.
  3. Quick prototypes of new projects — single-file scripts plus npm dependencies are smoothest here.
  4. Small full-stack on Deno Deploy — Fresh 2 plus Deno KV.
  5. Backend tooling centered on @std — stability of the standard library is attractive.

Where Bun fits:

  1. CI speed (bun install, bun test).
  2. CLI tooling (bun build --compile).
  3. Edge cold start.
  4. SQLite-heavy small services.

Where Node 22+ still fits:

  1. Most enterprise production.
  2. Environments where APM/observability matter.
  3. Large monorepos with native addons.
  4. Company-standard runtime — easy to hire for.

The three runtimes are not zero-sum. Within one company, Node (main services), Bun (CLI/CI), and Deno (AI-agent sandbox, high-security pieces) often coexist. The "one wins everything" narrative no longer fits 2026.


Chapter 11 · The npm-Compat Broken / Over-Delivered Edges

Over-delivered

  • Stability of deno install — landed smoother than Deno 1 users worried about.
  • npm: specifier compat — Express, Hono, Zod, the Prisma client, AWS SDK, and most major libs work.
  • deno deploy for npm packages — some npm modules that Cloudflare Workers cannot run (v8-isolate constraints) do run on Deno Deploy.
  • Deno KV GA — production-ready, dispelling early beta concerns.
  • JSR's score system — first serious standardization attempt for package quality, quickly anchored.

Broken / still weak

  • Native addons (N-API) — sharp, canvas, bcrypt and the like still hit friction. Improving, but not zero.
  • APM auto-instrumentation — Datadog and New Relic Node-level instrumentation does not transplant 1:1 onto Deno. Same weakness as Bun.
  • Debugger integration — Chrome DevTools protocol compatibility exists, but VS Code debugger stability lags Node by a step.
  • Fresh adoption — does not crack Next.js, even with Fresh 2's improvements.
  • JSR adoption — slow expansion outside the Deno ecosystem.
  • Deno 3 timeline opacity — the next big milestone remains fuzzy.

Chapter 12 · Who Is Running Deno 2 in Production

Case A — AI-agent sandbox

The clearest win zone. When permissions matter on model-generated code:

  • e2b, Modal, Replit — Deno appears as an option in some AI infrastructure.
  • Startups building their own code interpreters.
  • Self-hosted tool-use targets for Claude / GPT code execution.

Case B — Full-stack on Deno Deploy

Small full-stack built with Fresh 2 plus Deno KV:

  • Internal dashboards, micro SaaS.
  • API plus static-page hybrid services.
  • Small datasets that benefit from global read distribution.

Case C — Backend tooling heavy on the standard library

CLI tools and dev tools that lean on @std/cli, @std/path, @std/fs, @std/encoding. Places where minimal external dependencies are valuable.

Case D — Slack/Discord bots and webhook handlers

Small webhook services with Deno.serve plus Deno.openKv(). Permissions keep the blast radius small; global deploy via Deno Deploy.

Case E — Almost none — large enterprise monoliths

Same reasons as Bun. APM, debugger, team familiarity, weight of an existing codebase.

Named cases (from public posts)

  • Netlify Edge Functions — Deno-based runtime.
  • Supabase Edge Functions — Deno-based.
  • Slack/Salesforce automation — leveraging Deno's permission model.
  • Deno Deploy itself — eat your own dogfood.

Chapter 13 · Migration — Steps for Moving a Node Project to Deno 2

Staged adoption

  1. Adopt deno fmt and deno lint only — no other tool changes. A low-friction first step.
  2. Run deno test in CI — in parallel with Vitest/Jest. Verify the speed and zero-config TS appeal.
  3. Move a single script to Deno — start with one-off scripts like scripts/migrate.ts.
  4. Write a new small service in Deno — new microservice or internal tool.
  5. Use deno install for dependency management — keep Node runtime, swap install only.
  6. Move production runtime to Deno — the biggest step, last.

Adoption checklist

  • Does our APM (Datadog/NR/Sentry) support Deno? At what instrumentation depth?
  • Do our native-addon dependencies (sharp, canvas, bcrypt) work on Deno?
  • Can our CI image take Deno? Use the official denoland/deno image.
  • Will we actually narrow permissions in production? If we run with -A, the differentiator disappears.
  • Will we use Fresh 2 (Deno's first-party tools) or the Deno mode of Hono/Express?
  • What does the rollback scenario look like — cost of going Deno to Node?

Common anti-patterns

  • Turning on -A to grant all permissions and leaving it. Reduces the value of the permission model to zero.
  • Forcing Fresh as the full-stack default. Giving up Next.js ecosystem richness should require a real reason.
  • Publishing JSR-only. 80 percent of users are still on npm. Dual-publish.
  • Putting Deno KV in a relational-DB slot. Fits small read-heavy data; not transaction-heavy or join-heavy workloads.
  • Assuming deno run is a Node drop-in. Compat improved, not 100 percent. Measure critical paths.
  • Deciding from benchmark charts alone. Measure on your workload.

Epilogue — From Idealism to Pragmatism

Deno 1 was born as an explicit rebuttal to Node. Deno 2 withdrew half the rebuttal in favor of pragmatism. The result:

Deno gave up the "replace Node" narrative and adopted the "carve a meaningful space next to Node" narrative. That space is the AI-agent sandbox, Deno Deploy, and standard-library-centered tooling.

Things to remember:

  • Deno 2 made Node-code migration easier than expected. 90 percent just runs. Friction lives in native addons, APM, parts of debugging.
  • JSR did not kill npm, but it became the default inside the Deno ecosystem. TS-native publishing really is a clean win.
  • Fresh 2 is better, but it does not take Next.js's seat. Attractive inside the Deno Deploy bundle.
  • Deno KV is production-ready. Worth it as a one-line KV in small services.
  • The security model became more valuable in the AI era. Running model-generated code is Deno's natural home.
  • Deno 3 is not officially announced yet. Two large self-negations in a row are hard; expect incremental evolution.

Adoption checklist (before bringing Deno in)

  • Is yours a workload that genuinely needs the permission model, or are you going to turn it off with -A?
  • What is the bar for APM/observability? If full Datadog/NR instrumentation is mandatory, stay on Node for now.
  • Have you audited all native-addon dependencies?
  • Is your CI image and Dockerfile ready to add Deno?
  • Will you start with a new small service or migrate existing code? The former is almost always right.
  • Will you use Deno Deploy, or run Deno containers on your own infra (Kubernetes/Fly)?

Common anti-patterns (recap)

  • Turning on the permission model and granting everything, defeating the differentiator.
  • Forcing Fresh as the new-project default.
  • Placing Deno KV in a relational-DB slot.
  • Publishing JSR-only and ignoring the 80 percent on npm.
  • Assuming 100 percent compat for npm: imports.
  • Citing benchmark charts without measuring your own workload.

Next post previews

  • "AI agent sandbox runtime comparison 2026 — Deno, Bun, Firecracker microVM, gVisor" — five options for running model-generated code safely.
  • "Fresh vs Next.js vs Astro 2026 — three answers to islands architecture" — the SSR full-stack contest.
  • "Deno Deploy vs Cloudflare Workers vs Vercel Edge" — three edge-runtime giants compared.

References

Deno official

Deno 2 launch materials

  • "Deno 2.0" announcement post — the bet on Node compat and package.json support.
  • Deno 2 RFCs and design notes — the rationale for nodeModulesDir, workspace introduction.

JSR

  • JSR official — https://jsr.io/ — package search, score, docs.
  • JSR docs — TS-native publishing, scope management.
  • "Why JSR" post — Deno team's motivation, design choices.

Fresh

Deno KV

  • Deno KV docs — Deno.openKv() API, key structure, atomic transactions.
  • Deno KV GA blog post — production-ready declaration.
  • FoundationDB — the backend technology behind Deno Deploy's KV.

Deno Deploy

  • Deno Deploy — https://deno.com/deploy — global isolate runtime.
  • Deno Deploy pricing and limits — plans, per-key limits, edge constraints.

Node.js (for comparison)

  • Node.js official — https://nodejs.org/
  • Node --experimental-strip-types docs — running TS directly.
  • node:test docs — Node 22+ native test runner.

Bun (for comparison)

  • Bun official — https://bun.sh/
  • Bun runtime compatibility matrix — Node API compatibility status.

Security / permission model

  • Deno permission system docs — every --allow-* flag option.
  • OWASP supply-chain security — threat model for npm/JS.
  • xz-utils incident retrospective — how supply-chain attacks influenced the security-model bet.

Production adoption cases (from public posts)

  • Netlify Edge Functions engineering blog post on Deno adoption.
  • Supabase Edge Functions architecture — design of the Deno-based runtime.
  • Cases of adopting Deno for Slack automation.

Critical takes / retrospectives

  • "Why we did NOT pick Deno" startup posts — companies that explicitly chose not to.
  • Operations-team posts on the limits of APM auto-instrumentation.
  • Community reactions to Deno 2's self-negation (forums, Hacker News, Reddit).

Standards / WinterCG

  • WinterCG — https://wintercg.org/ — the cross-runtime JS standards group.
  • Web-interoperable runtimes spec — the standard Deno, Bun, Workers, and Vercel follow.

현재 단락 (1/329)

Ryan Dahl built Node in 2009. In 2018 at JSConf EU, he gave the famous "10 Things I Regret About Nod...

작성 글자: 0원문 글자: 22,764작성 단락: 0/329