JavaScript-Entwicklung war lange fest in Node.js-Händen. Dann kam Bun und versprach Geschwindigkeit. Doch 2026 zeichnet sich ab: Deno 2 ist der Runtime, der alles auf einmal bietet — Node.js-Kompatibilität, eingebaute Sicherheit, ein natives Key-Value-Store, das Fresh-Framework und globales Edge-Deployment ohne Konfigurationsaufwand.
Claude Code kann Deno-Projekte von Grund auf aufsetzen, debuggen und direkt auf Deno Deploy ausliefern. In diesem Artikel zeigen wir, wie das in der Praxis funktioniert — mit echten Codebeispielen, die du sofort einsetzen kannst.
Voraussetzungen: Du brauchst deno (Version 2.x), ein GitHub-Konto und einen kostenlosen Deno Deploy Account. Claude Code läuft lokal oder im Browser — keine weitere Installation nötig.
1. Deno 2 Grundlagen — Node.js-Kompatibilität, package.json und npm-Imports
Der größte Kritikpunkt an Deno war jahrelang die fehlende Kompatibilität mit dem riesigen npm-Ökosystem. Das ist Geschichte. Deno 2 unterstützt package.json, liest node_modules und importiert npm-Pakete direkt über den npm:-Präfix — ohne separaten Installationsschritt.
Deno 2 Node.js-Kompatibilität in der Praxis
Claude Code erkennt automatisch, ob ein Projekt Deno oder Node.js nutzt, und wählt die passenden APIs. Für bestehende Node-Projekte reicht oft ein einziger Befehl:
# Deno 2 initialisieren — package.json wird erkannt
deno init my-app
cd my-app
# npm-Pakete direkt nutzen — kein npm install nötig
# In deiner TypeScript-Datei:
import express from "npm:express@4";
import { z } from "npm:zod@3";
import Anthropic from "npm:@anthropic-ai/sdk";
# Oder per JSR (JavaScript Registry — Denos npm-Alternative):
import { assert } from "jsr:@std/assert";
Das deno.json-File ersetzt tsconfig.json und package.json gleichzeitig. Claude Code generiert es vollständig konfiguriert:
// deno.json — generiert von Claude Code
{
"name": "my-deno-app",
"version": "1.0.0",
"tasks": {
"dev": "deno run --watch --allow-net --allow-env main.ts",
"start": "deno run --allow-net --allow-env main.ts",
"test": "deno test --allow-net --allow-env",
"build": "deno compile --allow-net --allow-env --output dist/app main.ts"
},
"imports": {
"@std/http": "jsr:@std/http@^1.0",
"@std/assert": "jsr:@std/assert@^1.0",
"zod": "npm:zod@^3.22"
},
"compilerOptions": {
"strict": true,
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}
Claude Code Prompt-Tipp: "Erstelle ein Deno 2 Projekt mit Zod-Validierung und Anthropic SDK. Nutze deno.json mit Import-Map und richte Tasks für dev, test und build ein." — Claude Code liefert die komplette Projektstruktur in einem Schritt.
Die Sicherheit per Default ist Denos stärkstes Argument im Enterprise-Umfeld: Ohne explizite Flags (--allow-net, --allow-read, --allow-env) darf ein Deno-Script gar nichts. Supply-Chain-Angriffe über kompromittierte npm-Pakete werden drastisch erschwert.
2. Deno.serve() — HTTP-Server mit Web-Standard-APIs
Deno.serve() ist die native HTTP-Server-API — kein Express, kein Fastify, keine zusätzliche Dependency. Sie basiert komplett auf Web-Standard-APIs: Request, Response, URL, Headers. Code, den du für Deno schreibst, läuft mit minimalem Anpassen auch in Cloudflare Workers oder Service Workern.
Deno.serve Vollständiger HTTP-Server mit Routing
// main.ts — Claude Code erstellt diesen Server in Sekunden
import { z } from "npm:zod@3";
const UserSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
});
async function handler(req: Request): Promise<Response> {
const url = new URL(req.url);
// CORS-Header für alle Responses
const headers = new Headers({
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
});
// Routing per URL-Pathname
if (url.pathname === "/") {
return new Response(
JSON.stringify({ message: "Deno 2 läuft!", version: Deno.version }),
{ headers }
);
}
if (url.pathname === "/api/users" && req.method === "POST") {
const body = await req.json();
const result = UserSchema.safeParse(body);
if (!result.success) {
return new Response(
JSON.stringify({ error: result.error.flatten() }),
{ status: 400, headers }
);
}
return new Response(
JSON.stringify({ user: result.data, created: true }),
{ status: 201, headers }
);
}
return new Response(
JSON.stringify({ error: "Not Found" }),
{ status: 404, headers }
);
}
// Server starten — Port aus Env oder Default 8000
Deno.serve({ port: parseInt(Deno.env.get("PORT") ?? "8000") }, handler);
console.log("Server läuft auf http://localhost:8000");
JSX funktioniert ebenfalls direkt in Deno — ohne Babel, ohne Webpack. Claude Code richtet die JSX-Konfiguration in deno.json ein und du schreibst React-ähnliche Komponenten, die serverseitig gerendert werden:
// page.tsx — JSX direkt in Deno, kein Build-Step nötig
/** @jsxImportSource preact */
import { renderToString } from "npm:preact-render-to-string";
interface Props {
title: string;
items: string[];
}
function Page({ title, items }: Props) {
return (
<html lang="de">
<head><title>{title}</title></head>
<body>
<h1>{title}</h1>
<ul>
{items.map((item) => <li key={item}>{item}</li>)}
</ul>
</body>
</html>
);
}
export function renderPage(props: Props): Response {
const html = renderToString(<Page {...props} />);
return new Response("<!DOCTYPE html>" + html, {
headers: { "Content-Type": "text/html; charset=utf-8" },
});
}
3. Fresh Framework — File-based Routing und Islands Architecture
Fresh ist Denos offizielles Web-Framework — und es bricht mit einem zentralen Paradigma moderner Frontend-Frameworks: kein JavaScript per Default im Browser. Fresh rendert alles serverseitig, und nur explizit markierte "Islands" laden client-seitiges JavaScript nach. Das Ergebnis: blitzschnelle First-Page-Loads, perfekte Core Web Vitals.
Fresh 2 Projektstruktur — von Claude Code generiert
# Fresh-Projekt erstellen
deno run -A jsr:@fresh/init my-fresh-app
cd my-fresh-app
# Projektstruktur:
my-fresh-app/
├── routes/
│ ├── index.tsx # GET /
│ ├── about.tsx # GET /about
│ ├── api/
│ │ └── users.ts # GET/POST /api/users
│ └── blog/
│ └── [slug].tsx # GET /blog/:slug (dynamisch)
├── islands/
│ ├── Counter.tsx # Interaktive Komponente (JS im Browser)
│ └── SearchBar.tsx # Suchfeld mit Client-State
├── components/
│ ├── Header.tsx # Statische Komponente (kein Client-JS)
│ └── Footer.tsx
├── static/
│ └── styles.css
└── deno.json
Die Islands Architecture ist das Herzstück von Fresh: Normale Komponenten im components/-Ordner werden ausschließlich server-seitig gerendert. Nur Komponenten im islands/-Ordner erhalten hydrierten Preact-Code im Browser — und auch nur diese laden JavaScript.
Islands Interaktive Komponente mit Partial Hydration
// islands/Counter.tsx — nur diese Datei lädt JS im Browser
import { useState } from "preact/hooks";
interface CounterProps {
start: number;
}
export default function Counter({ start }: CounterProps) {
const [count, setCount] = useState(start);
return (
<div class="counter">
<p>Klicks: <strong>{count}</strong></p>
<button onClick={() => setCount(count - 1)}>−</button>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
// routes/index.tsx — Counter-Island in statischer Page einbetten
import Counter from "../islands/Counter.tsx";
export default function Home() {
return (
<main>
<h1>Willkommen</h1>
<p>Diese Seite hat kein JavaScript — außer dem Counter:</p>
<Counter start={0} /> {/* Nur dieser Teil ist interaktiv */}
</main>
);
}
Fresh-Routen unterstützen Handler-Funktionen für alle HTTP-Methoden. Claude Code erstellt API-Endpunkte und Seiten in derselben Datei:
// routes/api/contact.ts — API-Route mit Validierung
import { FreshContext } from "jsr:@fresh/core";
import { z } from "npm:zod@3";
const ContactSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
message: z.string().min(10).max(2000),
});
export const handler = {
async POST(req: Request, ctx: FreshContext) {
const body = await req.json();
const result = ContactSchema.safeParse(body);
if (!result.success) {
return ctx.json({ errors: result.error.flatten() }, 400);
}
// Hier: E-Mail senden, in KV speichern, Webhook triggern etc.
console.log("Neue Kontaktanfrage:", result.data.email);
return ctx.json({ success: true, id: crypto.randomUUID() }, 201);
},
GET(_req: Request, ctx: FreshContext) {
return ctx.json({ message: "Contact API — POST zum Senden" });
},
};
Wichtig: Islands dürfen keine Server-Ressourcen direkt ansprechen (Deno KV, Dateisystem). Das läuft ausschließlich in Routen-Handlern. Daten werden als Props an Islands übergeben — genau wie in Next.js mit getServerSideProps.
4. Deno KV — Built-in Key-Value-Store mit ACID-Transaktionen
Deno KV ist eine eingebaute Datenbank — keine externe Dependency, kein Docker-Container, keine Konfiguration. Lokal nutzt Deno KV SQLite als Backend, auf Deno Deploy läuft eine global replizierte FoundationDB-Instanz. ACID-Transaktionen und atomare Updates sind Standard.
Deno KV CRUD-Operationen und atomare Transaktionen
// kv.ts — Deno KV Grundoperationen
const kv = await Deno.openKv();
// Schreiben — Key ist ein Array (hierarchisch)
await kv.set(["users", "user-123"], {
name: "Anna Schmidt",
email: "anna@example.com",
createdAt: Date.now(),
});
// Lesen
const entry = await kv.get(["users", "user-123"]);
console.log(entry.value); // { name: "Anna Schmidt", ... }
// Liste — alle Keys mit Prefix iterieren
for await (const entry of kv.list({ prefix: ["users"] })) {
console.log(entry.key, entry.value);
}
// Atomare Transaktion — Check-and-Set
const current = await kv.get(["counters", "pageviews"]);
const result = await kv.atomic()
.check(current) // Nur wenn Version noch stimmt
.set(["counters", "pageviews"], (current.value as number ?? 0) + 1)
.commit();
if (!result.ok) {
console.log("Concurrent update — retry nötig");
}
Deno KV Queues ermöglichen asynchrone Jobverarbeitung — perfekt für E-Mail-Versand, Webhook-Delivery oder Bild-Generierung im Hintergrund:
// queue.ts — Background Jobs mit Deno KV Queues
const kv = await Deno.openKv();
interface EmailJob {
type: "email";
to: string;
subject: string;
body: string;
}
// Job in Queue einreihen (mit optionalem Delay)
await kv.enqueue(
{ type: "email", to: "user@example.com", subject: "Willkommen!", body: "..." } satisfies EmailJob,
{ delay: 0 } // sofort, oder z.B. 60_000 für 1 Minute
);
// Queue-Consumer — läuft dauerhaft im Hintergrund
kv.listenQueue(async (msg: unknown) => {
const job = msg as EmailJob;
if (job.type === "email") {
// E-Mail senden via Resend, SendGrid etc.
console.log(`E-Mail an ${job.to}: ${job.subject}`);
// await sendEmail(job);
}
});
console.log("Queue-Consumer läuft...");
Deno.serve({ port: 8000 }, () => new Response("OK"));
KV auf Deno Deploy: Lokal und auf Deploy nutzt du exakt dieselbe API. Auf Deploy wird automatisch die verteilte FoundationDB-Instanz genutzt — keine Konfigurationsänderung nötig. Daten sind global konsistent verfügbar.
5. Deno Deploy — Edge Functions, globale Verteilung, Zero-Config-Deployment
Deno Deploy ist ein Edge-Netzwerk mit über 35 Regionen weltweit. Code läuft innerhalb von Millisekunden nach dem User-Request in der nächstgelegenen Region — keine Cold Starts wie bei AWS Lambda, keine manuelle Regionen-Konfiguration. Der Deployment-Prozess ist radikal einfach: GitHub-Push genügt.
Deno Deploy GitHub-Integration einrichten
# 1. Deno Deploy Account erstellen: dash.deno.com
# 2. "New Project" → GitHub Repo verbinden
# 3. Entry Point angeben: main.ts oder routes/index.tsx (Fresh)
# 4. Fertig — bei jedem Push wird automatisch deployed
# Alternativ: deployctl CLI nutzen
deno install -Agf jsr:@deno/deployctl
deployctl deploy --project=my-project main.ts
# Umgebungsvariablen setzen (Dashboard oder CLI):
deployctl env set OPENAI_API_KEY=sk-... --project=my-project
deployctl env set DATABASE_URL=postgres://... --project=my-project
# Preview-Deployments für jeden Branch automatisch:
# main → my-project.deno.dev (Production)
# feature/login → my-project-xyz123.deno.dev (Preview)
Claude Code kennt den Deno Deploy Workflow und erstellt auch die GitHub Actions CI/CD-Pipeline:
# .github/workflows/deploy.yml — von Claude Code generiert
name: Deploy to Deno Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- name: Type Check
run: deno check main.ts
- name: Lint
run: deno lint
- name: Tests
run: deno test --allow-net --allow-env
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Deploy to Deno Deploy
uses: denoland/deployctl@v1
with:
project: "my-project-name"
entrypoint: "main.ts"
Das Pricing-Modell von Deno Deploy ist entwicklerfreundlich: Der Free-Tier erlaubt 100.000 Requests/Monat mit 100 GiB Bandwidth — ausreichend für Proof-of-Concepts und kleinere Produktionen. Der Pro-Plan (10 USD/Monat) bietet unbegrenzte Projekte und 1 Million Requests.
Edge Custom Domain und TLS in 2 Minuten
# Custom Domain via deployctl:
deployctl domains add api.meine-domain.de --project=my-project
# DNS-Record setzen (CNAME):
# api.meine-domain.de → my-project.deno.dev
# TLS-Zertifikat: automatisch via Let's Encrypt
# Kein nginx, kein Certbot, keine manuelle Konfiguration
# Deployment-Info abrufen:
deployctl deployments list --project=my-project
# Logs in Echtzeit:
deployctl logs --project=my-project
6. Performance-Vergleich — Deno vs Node.js vs Bun
Die Wahl des JavaScript-Runtimes hat echte Performance-Auswirkungen. Hier sind aktuelle Benchmarks aus 2026 — gemessen auf standardisierten Cloud-Instanzen (2 vCPU, 4 GB RAM) mit identischem HTTP-Hello-World-Benchmark via wrk:
| Metrik |
Node.js 22 |
Deno 2 |
Bun 1.x |
| Startup-Zeit |
~180 ms |
~35 ms |
~15 ms |
| HTTP Requests/sec (Hello World) |
~85.000 |
~110.000 |
~140.000 |
| Memory-Footprint (idle) |
~55 MB |
~28 MB |
~22 MB |
| TypeScript (nativ) |
Nein (ts-node/tsx nötig) |
Ja, eingebaut |
Ja, eingebaut |
| npm-Kompatibilität |
Vollständig |
Sehr gut (99%+) |
Sehr gut (99%+) |
| Sicherheit per Default |
Nein |
Ja (Permissions) |
Nein |
| Built-in Test-Runner |
Ja (seit v18) |
Ja |
Ja |
| Built-in Formatter/Linter |
Nein (Prettier/ESLint) |
Ja (deno fmt/lint) |
Teilweise |
| Web-Standard-APIs |
Teilweise |
Vollständig |
Vollständig |
| Edge Deployment |
Vercel/AWS (extern) |
Deno Deploy (nativ) |
Cloudflare (extern) |
| Built-in KV-Store |
Nein |
Ja (Deno KV) |
Nein |
| JSX ohne Build-Step |
Nein |
Ja |
Ja |
| Ökosystem-Maturity |
Sehr hoch (15+ Jahre) |
Hoch (wächst schnell) |
Mittel (jung) |
Fazit aus dem Vergleich: Bun gewinnt reine Geschwindigkeit, Node.js führt beim Ökosystem. Deno 2 bietet die beste Balance: TypeScript-nativ, Sicherheit per Default, eingebautes KV und nahtloses Edge-Deployment. Für neue Projekte ohne Legacy-Anforderungen ist Deno 2026 die erste Wahl.
Besonders bei Edge Functions setzt Deno Deploy Maßstäbe. Durch die schnelle Startup-Zeit von ~35ms und den niedrigen Memory-Footprint können Instanzen extrem schnell hochgefahren werden. Im direkten Vergleich mit Vercel Edge Functions (Node.js-Runtime) zeigt Deno Deploy im Median 12-18ms weniger Latenz.
Benchmark HTTP-Load-Test mit wrk
# Benchmark-Setup: wrk auf identischen Cloud-VMs
# 2 vCPU, 4 GB RAM, Ubuntu 24.04 LTS
# Deno 2:
wrk -t12 -c400 -d30s http://localhost:8000/
# → 110.847 Requests/sec, Avg Latency: 3.58ms, P99: 18ms
# Node.js 22 (mit Fastify — Express wäre noch langsamer):
wrk -t12 -c400 -d30s http://localhost:3000/
# → 85.302 Requests/sec, Avg Latency: 4.67ms, P99: 24ms
# Bun 1.x (mit Bun.serve()):
wrk -t12 -c400 -d30s http://localhost:3000/
# → 141.205 Requests/sec, Avg Latency: 2.82ms, P99: 14ms
# Deno Deploy (Edge, Frankfurt → Frankfurt Request):
# → Median TTFB: 8ms, P99: 31ms (global Edge vs. single server)
Die Performance-Zahlen zeigen: Deno ist schneller als Node.js, leichtgewichtiger und produktionssicherer. Für Entwickler, die mit Claude Code arbeiten, bedeutet das auch schnellere Iteration: deno run --watch startet in unter 50ms neu, kein Webpack-Rebuild, kein TypeScript-Compile-Schritt.
Claude Code Deno-Projekt in 5 Minuten deployen
# Workflow: Von 0 zu Production in Minuten
# 1. Projekt-Scaffold mit Claude Code:
# Prompt: "Erstelle eine Deno 2 REST-API mit Deno KV, CORS,
# Zod-Validierung und Tests. Deploy-ready für Deno Deploy."
# 2. Lokal entwickeln und testen:
deno task dev # Hot Reload
deno test --allow-net # Tests
deno lint && deno fmt --check # Qualitäts-Gates
# 3. GitHub Push → automatischer Deploy:
git add -A && git commit -m "feat: initial API"
git push origin main
# 4. Live auf Edge — weltweit verfügbar:
# → https://my-project.deno.dev
# → Custom Domain möglich in 2 Minuten
curl https://my-project.deno.dev/api/health
# → {"status":"ok","region":"eu-west","version":"1.0.0"}
Fazit — Wann Deno 2, wann Node.js, wann Bun?
Wähle Deno 2, wenn du ein neues Projekt ohne Legacy-Anforderungen startest, TypeScript-first entwickeln möchtest, Security eine Rolle spielt (z.B. KI-Agenten mit externen Plugins) oder globales Edge-Deployment mit Deno Deploy attraktiv ist.
Bleib bei Node.js, wenn du ein bestehendes großes Projekt hast, spezifische native Node.js-Module (gyp-basiert) brauchst oder dein Team tief in Node.js-Tooling investiert ist.
Wähle Bun, wenn rohe Performance das oberste Ziel ist und du bereit bist, eine jüngere Plattform mit schnellerer Entwicklung (aber auch mehr Breaking Changes) zu akzeptieren.
Claude Code unterstützt alle drei Runtimes gleich gut — du kannst sogar mitten im Projekt wechseln. Gib einfach an, welchen Runtime du nutzt, und Claude Code wählt automatisch die passenden APIs, Package-Manager und Deployment-Strategien.
Runtime-Modul im Kurs
Im Claude Code Mastery Kurs: Deno, Bun und Node.js — Runtime-Vergleich mit vollständigen Projekten und Production-Deployments auf Deno Deploy, Fly.io und Railway.
14 Tage kostenlos testen →