Deno 2 is a major release that brings full Node.js/npm compatibility while keeping Deno's security, built-in TypeScript, and developer experience. Run npm packages, use Node.js APIs, and deploy anywhere.
Why Deno 2?
- Node.js compatible — run most npm packages without changes
- TypeScript built-in — no tsconfig, no build step
- Secure by default — explicit permissions for file, network, env
-
npm support —
npm:specifier, node_modules optional - Built-in tools — formatter, linter, test runner, benchmarker
Install
curl -fsSL https://deno.land/install.sh | sh
# Or
brew install deno
Node.js Compatibility
// Use npm packages directly!
import express from 'npm:express@4';
import pg from 'npm:pg';
import chalk from 'npm:chalk';
const app = express();
app.get('/', (req, res) => {
res.json({ message: chalk.green('Hello from Deno 2!') });
});
app.listen(3000, () => console.log('Server running'));
# Run with network permission
deno run --allow-net server.ts
# Or allow all (development)
deno run -A server.ts
Built-in HTTP Server
// Deno native API — simpler than Express
Deno.serve({ port: 3000 }, async (req) => {
const url = new URL(req.url);
if (url.pathname === '/api/users' && req.method === 'GET') {
return Response.json([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
]);
}
if (url.pathname === '/api/users' && req.method === 'POST') {
const body = await req.json();
return Response.json({ id: 3, ...body }, { status: 201 });
}
return new Response('Not Found', { status: 404 });
});
Built-in Tools
# Format code (like Prettier)
deno fmt
# Lint (like ESLint)
deno lint
# Test
deno test
# Benchmark
deno bench
# Type check
deno check main.ts
# Compile to single binary
deno compile --output myapp main.ts
# Generate docs
deno doc main.ts
Testing (Built-in)
// users_test.ts
import { assertEquals } from 'jsr:@std/assert';
Deno.test('add user', async () => {
const response = await fetch('http://localhost:3000/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice' }),
});
const user = await response.json();
assertEquals(user.name, 'Alice');
assertEquals(response.status, 201);
});
deno test --allow-net
KV (Built-in Key-Value Database)
const kv = await Deno.openKv();
// Set
await kv.set(['users', 'alice'], { name: 'Alice', email: 'alice@example.com' });
// Get
const entry = await kv.get(['users', 'alice']);
console.log(entry.value); // { name: 'Alice', email: 'alice@example.com' }
// List
const iter = kv.list({ prefix: ['users'] });
for await (const entry of iter) {
console.log(entry.key, entry.value);
}
// Atomic transactions
await kv.atomic()
.set(['users', 'bob'], { name: 'Bob' })
.set(['user_count'], new Deno.KvU64(2n))
.commit();
Permissions (Security)
# Granular permissions
deno run --allow-net=api.example.com --allow-read=./data --allow-env=API_KEY main.ts
# Permission prompt (interactive)
deno run main.ts
# ┌ ⚠️ Deno requests net access to "api.example.com"
# ├ Allow? [y/n/A]
Key Features
| Feature | Details |
|---|---|
| npm support | Full compatibility via npm:
|
| TypeScript | Built-in, zero config |
| Security | Explicit permissions |
| Tools | fmt, lint, test, bench, doc, compile |
| KV | Built-in key-value database |
| Deploy | Deno Deploy, Docker, any platform |
Resources
Building with Deno? Check my Apify actors or email spinov001@gmail.com.
Top comments (0)