Deno & Modern Runtimes
Build with Deno and Bun: native TypeScript, secure by default permissions, Deno KV, Bun workspaces, and choosing between runtimes for your use case.
Deno and Bun are modern JavaScript runtimes that address Node.js pain points. Deno offers secure-by-default execution, native TypeScript, a standard library, and edge deployment. Bun prioritizes speed and Node.js compatibility. Both are production-ready for specific use cases.
Use Deno for edge functions, scripts needing security isolation, and greenfield TypeScript APIs. Use Bun when you need Node.js compatibility with faster installs and test runs. Stay on Node.js for existing production codebases unless there's a specific reason to migrate.
Workflow
- Build with DenoDeno runs TypeScript natively with secure-by-default permissions - no `npm install`, no `tsconfig.json` needed.
- Use Deno KV for storageDeno KV is a built-in key-value store in Deno - no separate database setup needed for simple storage.
- Deploy to Deno DeployDeno Deploy is a globally distributed edge runtime - zero config deployment for Deno scripts.
- Use Bun for speedBun is a fast Node.js-compatible runtime - installs npm packages 10-25x faster, runs tests 3x faster.
- Choose the right runtimeRuntime choice affects ecosystem compatibility, performance, and operational complexity.
Output Format
Deno with explicit permission flags and `deno.json` tasks, Deno KV for simple storage, Deno Deploy for edge, Bun for npm-compatible fast scripts, runtime choice matrix based on requirements.
Examples
Deno HTTP server: `Deno.serve({ port: 8080 }, async (req: Request) => { const url = new URL(req.url); if (url.pathname === "/health") return new Response("OK"); const kv = await Deno.openKv(); const count = (await kv.get<number>(["visits"])).value ?? 0; await kv.set(["visits"], count + 1); return Response.json({ visits: count + 1 }) })`Bun test: `import { describe, expect, it } from "bun:test"; describe("math", () => { it("adds numbers", () => { expect(2 + 2).toBe(4) }) })` // run with: bun testDeno task: `{ "tasks": { "dev": "deno run --watch --allow-net --allow-env --allow-read main.ts", "test": "deno test --allow-net", "check": "deno check main.ts" }, "imports": { "@std/http": "jsr:@std/http@^1.0" } }`Edge Cases & Gotchas
- npm compatibility in Deno: `npm:` specifier works for most packages, but packages using Node.js built-ins (child_process, fs with callbacks) may need the `--unstable-*` flag. Check compatibility at `deno.land/ecosystem`
- Bun native modules: Bun cannot run native Node.js addons (`.node` files compiled from C++). If your dependency uses native modules (sharp, bcrypt, sqlite3), use Node.js or the Bun-native alternatives
- Deno permissions in production: be specific with permissions - `--allow-net=api.stripe.com` instead of `--allow-net` - principle of least privilege applies even to your own code
When to Break These Rules
- For production apps already running on Node.js with stable infrastructure, migrating to Deno or Bun for its own sake is rarely worth the risk. The gain must outweigh the migration cost and reduced ecosystem compatibility.
Reference Files
Deno docs: https://docs.deno.com/Deno KV: https://docs.deno.com/kv/Deno Deploy: https://deno.com/deployBun docs: https://bun.sh/docs