Deno 2: What Changed and Why It Matters
Deno 2 launched in October 2024 and addressed the biggest complaint about Deno 1: it didn't work with the npm ecosystem. Deno 1 required everything to be imported from URLs, which meant most existing Node.js packages couldn't be used without extra tooling.
Deno 2 changes the compatibility story completely while keeping the security model, built-in tooling, and TypeScript-first approach that made Deno 1 interesting.
What's New in Deno 2
1. Node.js Compatibility
Deno 2 supports node: imports and can run most Node.js code without modification:
import { readFileSync } from "node:fs";
import { createServer } from "node:http";
import path from "node:path";
The Node.js standard library (node:fs, node:http, node:path, etc.) is implemented in Deno's runtime. Code that uses only Node built-ins typically runs without changes.
2. npm Package Support
Import npm packages directly using the npm: specifier:
import express from "npm:express@4";
import { z } from "npm:zod";
import chalk from "npm:chalk";
Deno downloads and caches npm packages locally, similar to how npm works. You don't need a separate npm install step — Deno handles package resolution automatically.
3. JSR: The New Package Registry
Deno introduces the JavaScript Registry (jsr.io), designed as a successor to npm for TypeScript-first packages:
- Packages publish TypeScript directly (no pre-compilation required)
- JSR generates documentation from types
- Compatibility with both Deno and Node.js
- Score-based quality metrics
Import JSR packages with the jsr: specifier:
import { assertEquals } from "jsr:@std/assert";
import { Hono } from "jsr:@hono/hono";
The @std/ scope contains Deno's standard library — previously imported from URLs (https://deno.land/std), now from JSR.
4. Workspaces
Deno 2 supports monorepos with workspaces:
// deno.json (root)
{
"workspace": ["./packages/*"]
}
// packages/api/deno.json
{
"name": "@myorg/api",
"version": "1.0.0",
"exports": "./src/index.ts"
}
5. LTS Releases
Deno 2 introduced Long-Term Support releases with 6 months of security patches. For production deployments, use an LTS release for stability.
6. deno install for Project Dependencies
Deno 2 adds deno install for managing project dependencies (similar to npm install):
deno install # install dependencies from deno.json
deno add jsr:@std/path # add a JSR dependency
deno add npm:express # add an npm dependency
Dependencies are tracked in deno.json:
{
"imports": {
"@std/path": "jsr:@std/path@^1.0.0",
"express": "npm:express@^4.18.0"
}
}
Getting Started
Install Deno:
# macOS/Linux
curl -fsSL https://deno.land/install.sh | sh
# Windows
irm https://deno.land/install.ps1 | iex
# Homebrew
brew install deno
Create a project:
deno init my-project
cd my-project
deno run main.ts
Run with npm packages:
// main.ts
import Fastify from "npm:fastify";
const app = Fastify();
app.get("/", async () => {
return { hello: "world" };
});
await app.listen({ port: 3000 });
deno run --allow-net main.ts
The Permission Model
Deno's permission model is unchanged from v1 — you must explicitly grant permissions:
# Allow network access
deno run --allow-net script.ts
# Allow specific host only
deno run --allow-net=api.example.com script.ts
# Allow file read/write
deno run --allow-read --allow-write script.ts
# Allow environment variables
deno run --allow-env script.ts
# Allow all (not recommended for untrusted code)
deno run --allow-all script.ts
In Deno 2, you can configure permissions in deno.json:
{
"tasks": {
"start": "deno run --allow-net --allow-read src/main.ts"
}
}
Built-in Tooling
Deno includes tools that Node.js needs separate packages for:
| Tool | Deno | Node.js equivalent |
|---|---|---|
| TypeScript | Built-in, no config | tsc or ts-node |
| Formatter | deno fmt |
Prettier |
| Linter | deno lint |
ESLint |
| Test runner | deno test |
Jest, Vitest |
| Bundler | deno bundle |
esbuild, Rollup |
| Docs generator | deno doc |
JSDoc + typedoc |
| REPL | deno repl |
node |
| Task runner | deno task |
npm scripts |
No package.json scripts, no tsconfig.json, no separate formatter config.
Run tests:
// math.test.ts
import { assertEquals } from "jsr:@std/assert";
Deno.test("addition", () => {
assertEquals(1 + 1, 2);
});
Deno.test("async test", async () => {
const result = await fetch("https://example.com");
assertEquals(result.status, 200);
});
deno test
deno test --coverage # with coverage report
Migrating Node.js Code to Deno 2
Most Node.js code requires minimal changes:
1. Replace npm imports with npm: specifiers:
// Node.js
import express from "express";
// Deno 2
import express from "npm:express";
2. Replace standard library require with node: prefix:
// Node.js
const fs = require("fs");
const { join } = require("path");
// Deno 2 (ES modules)
import { readFileSync } from "node:fs";
import { join } from "node:path";
3. Add permissions flags for your script's requirements
4. Replace package.json scripts with deno.json tasks:
{
"tasks": {
"start": "deno run --allow-net --allow-read src/main.ts",
"dev": "deno run --watch --allow-net src/main.ts",
"test": "deno test"
}
}
Deno 2 vs. Node.js vs. Bun
| Aspect | Deno 2 | Node.js | Bun |
|---|---|---|---|
| TypeScript | Built-in, zero config | Via tsc/ts-node | Built-in |
| Security model | Permissions required | Full access | Full access |
| npm compatibility | Yes (npm: specifier) | Native | Yes |
| Package manager | deno install | npm/pnpm/yarn | bun install (fast) |
| Package registry | JSR + npm | npm | npm |
| Startup speed | Fast | Moderate | Very fast |
| HTTP performance | Good | Good | Very good |
| Maturity | Stable, LTS | Very mature | Maturing |
| Windows support | Good | Excellent | Good |
| Ecosystem | npm + JSR | npm | npm |
Choose Deno 2 if:
- You want TypeScript without configuration overhead
- Security sandboxing matters (running untrusted scripts, serverless)
- You prefer a batteries-included toolchain without separate formatter/linter setup
- You're building CLI tools or scripts with untrusted dependencies
Choose Node.js if:
- You need the broadest npm ecosystem compatibility (some packages still have Deno issues)
- Your team knows Node.js deeply
- You're running existing Node.js code in production
Choose Bun if:
- Raw performance is the priority (Bun is fastest for startup and HTTP)
- You want the Node.js compatibility model with better speed
- You're comfortable with a less mature runtime
Deno Deploy
Deno Deploy is Deno's serverless edge platform — zero-config deployment for Deno apps. If you're building APIs or web apps with Deno, it's the simplest deployment target:
deployctl deploy --project=my-app main.ts
Deploys to Deno's global edge network. Free tier available for small projects.
Deno 2's full changelog is at deno.land and the GitHub repository is denoland/deno.