All posts
denoruntimebackend

Deno: A Practical Guide for Full-Stack Developers

A practical guide to Deno — secure-by-default permissions, native TypeScript, Web Standard APIs, and how it compares to Node.js and Bun.

SR

Suhail Roushan

August 6, 2026

·
4 min read
·
0 views

Deno was built by Node.js's original creator specifically to fix what he considered Node's biggest design mistakes, and the permission system is the clearest example of that philosophy in practice.

Deno is a JavaScript/TypeScript runtime built on V8 (the same engine as Node and Chrome) with secure-by-default execution — scripts can't access the filesystem, network, or environment variables unless explicitly granted permission — native TypeScript support with no config, and built-in tooling (formatter, linter, test runner, bundler) as part of the runtime itself rather than separate npm packages.

Why Deno Matters (and When to Skip It)

The permission model is Deno's standout feature: running deno run script.ts with no flags means the script can't touch your filesystem, network, or environment at all. You explicitly grant --allow-net, --allow-read, --allow-env as needed. For running third-party or AI-generated scripts, or for sandboxed execution environments, this is a genuine security advantage Node.js has no equivalent for.

Skip Deno if your project depends heavily on Node-specific native addons or npm packages with deep Node API assumptions — while Deno has strong npm compatibility now, some edge cases still don't transfer cleanly.

Getting Started with Deno

No package.json, no config needed to run TypeScript directly:

curl -fsSL https://deno.land/install.sh | sh
deno run --allow-net server.ts
Deno.serve({ port: 3000 }, (req: Request) => {
  const url = new URL(req.url);
  if (url.pathname === "/health") {
    return Response.json({ status: "ok" });
  }
  return new Response("Not found", { status: 404 });
});

Try running this without --allow-net and Deno refuses at runtime with a clear permission error — that's the security model working as intended, not a bug.

Core Deno Concepts Every Developer Should Know

Permissions are granted per-capability, not all-or-nothing. You can allow network access to specific hosts only (--allow-net=api.example.com), or filesystem access to specific paths (--allow-read=/tmp) — much finer-grained than Node's implicit full access.

Built-in tooling removes entire dependency categories. deno fmt, deno lint, deno test, and deno bundle ship with the runtime — no Prettier, ESLint, Jest, or Webpack config needed for a baseline setup:

Deno.test("adds two numbers", () => {
  const result = 1 + 1;
  if (result !== 2) throw new Error("math is broken");
});

Run with deno test — no config file required.

Deno uses Web Standard APIs wherever possible, similar in philosophy to Hono — fetch, Request/Response, WebSocket, and Web Crypto are all built in and behave like their browser counterparts, reducing the gap between browser and server code.

npm compatibility has matured significantly. Modern Deno supports npm: specifiers directly in import statements, letting you pull in npm packages without a separate install step:

import { z } from "npm:zod@^3.22";

Common Deno Mistakes and How to Fix Them

Mistake 1: forgetting permission flags and assuming a crash is a bug. A script that silently fails to read a file or make a network call, with a permission-denied error, is Deno working correctly — not broken. Fix: read the error message; it tells you exactly which --allow-* flag is missing.

Mistake 2: over-granting --allow-all out of convenience. This defeats the entire security model that's Deno's main differentiator. Fix: grant only the specific permissions a script actually needs, especially for anything running untrusted or third-party code.

Mistake 3: assuming every npm package works identically. Some npm packages rely on Node internals Deno doesn't fully replicate. Fix: test critical dependencies under Deno before committing to a migration, and check the package's Deno compatibility notes if available.

When Should You Use Deno Instead of Node.js or Bun?

Use Deno when running untrusted code, building CLIs or scripts where the permission model adds real safety, or when you want built-in tooling without assembling a toolchain. Choose Node.js for maximum ecosystem compatibility with existing tooling, or Bun when raw speed and an all-in-one binary matter more than the permission model.

Deno in Production

Deno Deploy (Deno's own edge hosting) is a natural pairing if you're already using Deno, offering globally distributed execution with the same permission model. For teams running AI-generated or plugin-style user code, Deno's sandboxing is worth strong consideration specifically because it makes "run this code but don't let it touch the filesystem" a first-class, enforced guarantee rather than something you build yourself.

If you're building anything that executes code you don't fully control — plugins, AI-generated scripts, user-submitted functions — evaluate Deno's permission model before reaching for a heavier VM-based sandbox.

Related posts

Written by Suhail Roushan — Full-stack developer. More posts on AI, Next.js, and building products at suhailroushan.com/blog.

Get in touch