JavaScript · TypeScript · WASM Runtime — Reference Cheat Sheet

deno

v2.9 V8 · Rust · Tokio 🔒 secure by default

Secure-by-default runtime for JS, TS & WASM: no file, network, or env access until you grant it. Built-in TypeScript, web-standard APIs, and an all-in-one toolchain (fmt, lint, test, compile) — plus JSR, npm & Node compatibility. By Ryan Dahl, creator of Node.

CLI & toolchain permissions & security modules & deps runtime APIs setup / config new / unstable gotcha ★ most common
Verified by running Deno 2.9.4 in-container (the permission sandbox live — NotCapable then --allow-read; native TS; deno test; deno fmt/lint; init) & cross-checked against docs.deno.com. V8 15 · TypeScript 6.

The mental model — a locked sandbox you open one door at a time

A · SECURE BY DEFAULT — EVERYTHING DENIED UNTIL YOU GRANT IT 🔒 SANDBOX deno run app.ts your code + all its dependencies DENIED by default ✗ ✗ disk read/write ✗ network ✗ env vars ✗ subprocess / ffi you open specific doors ✓ --allow-net=api.example.com --allow-read=./data --allow-env=PORT -A = allow ALL (skips sandbox) Why it matters A malicious dependency can’t read your SSH keys or phone home — it has no ambient access at all. Grant the minimum: scope to hosts & paths, not -A. --deny-* overrides allow · --no-prompt to fail hard. unlike Node, where every dep gets full system access B · ONE BINARY = THE WHOLE TOOLCHAIN deno native TS + WASM run fmt lint test bench compile doc check Replaces a pile of Node tooling node + ts-node → deno run · tsc → deno check · prettier → deno fmt eslint → deno lint · jest → deno test · pkg → deno compile zero config · imports from JSR, npm, node: and URLs C · THE SANDBOX, PROVEN (real output captured this build) $ deno run read.ts error: Uncaught NotCapable: Requires read access to "/etc/hostname", run again with the --allow-read flag $ deno run --allow-read=/etc read.ts  ✓ vm $ deno test adds ... ok · steps ... ok (a, b) ok | 2 passed (2 steps) | 0 failed native TS, no config, no jest install

Key insight: Deno flips Node’s trust model. Code starts with zero access to the disk, network, or environment; you grant exactly what a program needs with --allow-* flags (scoped to hosts and paths). A dependency can’t quietly exfiltrate data it was never allowed to touch.

Part I

CLI & Toolchain

01Install & init
  • curl -fsSL https://deno.land/install.sh | sh
    One binary; also brew, npm, scoop, docker.
  • deno upgrade deno upgrade canary # self-update
  • deno --version # deno 2.9 · V8 · TypeScript
  • deno init myproj # scaffold deno.json + main.ts
  • Built on V8 + Rust + Tokio · runs JS, TS & WASM.
02Run & eval
  • deno run app.ts deno app.ts # sandboxed by default
    No file/net/env access until granted.
  • deno run -A app.ts # -A = allow ALL (skips sandbox)
  • deno run --watch app.ts # restart on change
  • deno serve -A server.ts # run an HTTP server
    Uses export default { fetch }.
  • deno eval 'console.log(1+2)' deno repl
  • Runtime flags go before the script; args after → Deno.args.
03Tasks
  • deno task dev # run a task from deno.json
  • "tasks": { "dev": "deno run --watch -N main.ts" }
    Defined in deno.json.
  • deno task # list available tasks
  • Tasks run in a cross-platform shell (built in).
  • deno task test -- --filter x # pass args after --
04Format · lint · check
⚑ no prettier / eslint / tsc
  • deno fmt deno fmt --check # built-in formatter
  • deno lint # built-in linter
  • deno check main.ts # explicit type-check
    run does NOT type-check by default.
  • deno doc mod.ts deno doc --html # docs from JSDoc
  • deno info main.ts # module graph + cache paths
05Test & bench
  • deno test deno test --coverage
    Built-in runner — no jest.
  • Deno.test("adds", () => assertEquals(2+2, 4))
  • Deno.test("x", async (t) => { await t.step("a", ...) })
    Nested steps.
  • deno test --watch --filter "user"
  • deno bench # benchmarks
  • Deno.bench("loop", () => { ... })
06Compile & bundle
  • deno compile -A app.ts # single self-contained exe
    Ships the runtime + your code.
  • deno compile --target x86_64-pc-windows-msvc app.ts
    Cross-compile.
  • deno compile --include ./assets app.ts
    Embed extra files.
  • deno bundle main.ts # bundle to one JS file
  • deno pack # create an npm-compatible tarball
Part II

Permissions & Security

07Secure by default
  • No disk, network, env, or subprocess access unless granted.
    The core of Deno’s security model.
  • NotCapable: Requires read access to "/x", run again with --allow-read
    What you see without a flag.
  • Grant via CLI flags or an interactive runtime prompt.
  • Deps get no ambient access — unlike Node.
    Supply-chain safety.
  • All code on a thread shares one privilege level.
08Allow flags
  • -R, --allow-read · -W, --allow-write — filesystem
  • -N, --allow-net — network
  • -E, --allow-env · -S, --allow-sys — env & OS info
  • --allow-run — subprocesses · --allow-ffi — native libs
  • -I, --allow-import — remote imports
  • -A, --allow-all — everything (gives up the sandbox).
    Avoid in production.
09Scoped & deny
  • deno run --allow-net=api.example.com,localhost:8080 app.ts
    Allow-list specific hosts.
  • deno run --allow-read=./data --allow-write=./tmp app.ts
    Scope to paths.
  • deno run -N=api.example.com -E app.ts # short forms
  • --deny-net / --deny-read — override allow (deny wins).
  • --no-prompt — throw instead of prompting.
    Good for CI.
10Runtime permissions
  • await Deno.permissions.query({ name: "read", path: "./x" })
    Check state at runtime.
  • await Deno.permissions.request({ name: "net" })
    Prompt on demand.
  • await Deno.permissions.revoke({ name: "write" })
    Drop a permission.
  • .querySync() — sync counterparts exist.
  • State is "granted" / "denied" / "prompt".
Part III

Modules, Deps & Config

11ES Modules & imports
  • import { x } from "./mod.ts"; export const y = 1
    ESM only — no require.
  • Imports need the extension: ./util.ts.
  • Top-level await is allowed.
  • import.meta.url · import.meta.dirname · import.meta.main
    No __dirname.
  • await import("./x.ts") — dynamic import
12Specifiers: jsr / npm / node
  • import { assert } from "jsr:@std/assert"
    JSR — the TS-first registry.
  • import express from "npm:express@4"
    npm packages, directly.
  • import { readFile } from "node:fs/promises"
    Node built-ins.
  • import { x } from "https://example.com/mod.ts"
    URL imports (needs --allow-import).
  • Bare specifiers resolve via the import map in deno.json.
13Dependency management
  • deno add jsr:@std/http deno add npm:zod
    Writes deno.json + deno.lock.
  • deno install deno ci # ci = clean, reproducible
  • deno remove zod deno outdated
  • deno why zod # explain why a pkg is installed
  • deno audit deno audit fix # vuln scan + fix
  • Commit deno.lock; it pins integrity hashes.
14deno.json config
  • "imports": { "@std/assert": "jsr:@std/assert@1" }
    The import map.
  • "tasks" · "compilerOptions" · "lint" · "fmt"
    One config for everything.
  • "workspace": ["./a", "./b"] — monorepo
  • Also reads package.json (Node compat).
  • "nodeModulesDir": "auto" when npm deps need it.
15JSR & publishing
  • JSR (jsr.io) — TS-native registry, works with Deno/Node/Bun.
  • deno publish # publish to JSR (no build step)
    Auto-generates types & docs.
  • deno publish --dry-run
  • deno pack # emit an npm-compatible tarball
  • Versioned, immutable, provenance-tracked.
Part IV

Runtime APIs

16HTTP server
  • Deno.serve((req) => new Response("hi"))
    Web-standard RequestResponse.
  • Deno.serve({ port: 8000 }, handler)
  • Deno.serve({ routes: { "/api/:id": (req) => ... } })
    Built-in routing.
  • const { socket, response } = Deno.upgradeWebSocket(req)
    WebSockets.
  • Or export default { fetch } + deno serve
17File & system
  • await Deno.readTextFile("f.txt") / writeTextFile
    Needs --allow-read/-write.
  • using f = await Deno.open("f", { read: true })
    FsFile handle (auto-close with using).
  • Deno.env.get("PORT") · Deno.env.set(...)
    Needs --allow-env.
  • Deno.args · Deno.cwd() · Deno.exit(1)
  • Deno.stat / mkdir / remove / makeTempFile
18Web-standard globals
⚑ no import needed
  • fetch(url) · Request · Response · Headers
    Same as the browser.
  • ReadableStream / WritableStream / TransformStream
  • crypto.randomUUID() · crypto.subtle.digest(...)
    Web Crypto.
  • WebSocket · URL · URLSearchParams
  • structuredClone · setTimeout · addEventListener
  • new Worker(url, { type: "module" }) — web workers
19Subprocess & utilities
  • new Deno.Command("git", { args: ["status"] })
    Needs --allow-run.
  • const { stdout } = await cmd.output()
  • for await (const e of Deno.watchFs("./src")) {}
    File watcher.
  • Deno.inspect(obj) · Deno.build.os · Deno.version
  • Deno.makeTempFile() · Deno.realPath()
20Unstable & Node compat
  • const kv = await Deno.openKv() — built-in KV store
    Needs --unstable-kv.
  • Deno.dlopen(path, symbols) — FFI to native libs
    Needs --allow-ffi.
  • Deno 2 is Node/npm compatible: run existing projects.
    Reads package.json, node_modules.
  • node: built-ins & npm: specifiers work out of the box.
  • DENO_COMPAT=1 — Node compatibility mode.
21Gotchas & pitfalls
  • Forgetting --allow-*NotCapable.
    Grant the specific permission.
  • Flags after the script become Deno.args, not permissions.
    Put runtime flags first.
  • deno run does not type-check — use deno check
  • -A gives up the whole sandbox — prefer scoped flags.
  • No __dirname — use import.meta.dirname / .url
  • URL imports need --allow-import; Deno.openKv/FFI are unstable.

Four ideas worth a diagram

The distinctions that make Deno “Deno”.

1 · The permission model

Default-deny for every sensitive capability — grant the minimum.

DENIED unless a flag is passed read → -R --allow-read write → -W --allow-write net → -N --allow-net env → -E --allow-env run → --allow-run sys → -S --allow-sys ffi → --allow-ffi grant Scoped grants (allow-list) --allow-net=api.com,localhost:8080 --allow-read=./data -N=host -E grant only what the program needs -A / --allow-all opens everything — convenient, but no guarantees --deny-* wins over --allow-* --no-prompt throws instead of asking at runtime

2 · Where modules come from

Import by specifier — no node_modules required.

jsr:@std/assert npm:express@4 node:fs/promises https://esm.sh/x ./local.ts import map deno.json “imports” code deno add jsr:@std/http writes the map + deno.lock; cached globally, not per-project.

3 · Deno vs Node

Same creator, opposite defaults — and Deno 2 runs Node projects too.

deno node security sandbox, deny-allfull access TypeScript built-in, zero-configstrip-only (24+) HTTP / APIs web-standardnode: core modules config deno.jsonpackage.json tooling all-in-onenpm + many tools modules jsr / npm / urlnpm Deno 2 is Node-compatible — run existing package.json projects & use npm:/node:.

4 · Web-standard first

Learn the platform once; Deno.* only where no standard exists.

Web standard (same as browser) fetch() Request Response ReadableStream Headers crypto.subtle WebSocket URL structuredClone addEventListener Worker portable to browsers & edge Deno.* (no web standard exists) Deno.serve() — HTTP server Deno.readTextFile writeFile Deno.open — FsFile handle Deno.Command — subprocess Deno.env Deno.args Deno.cwd the parts a browser can’t do

Worth memorizing

deno runSECURE BY DEFAULT — no disk/net/env access until you pass --allow-*.
scoped grants--allow-net=api.com, --allow-read=./data; short: -N=host -E.
-A / --deny-*-A = allow all (gives up the sandbox); --deny-* overrides allow.
flags firstruntime flags go BEFORE the script; anything after → Deno.args.
native TSruns .ts zero-config; run does NOT type-check — use deno check.
ESM onlyimport/export; no require; imports need file extensions.
specifiersjsr:@std/x · npm:pkg · node:fs · https://… · ./local.ts.
deno.jsonimport map + tasks + fmt/lint/compilerOptions; run tasks with deno task.
all-in-onedeno fmt · lint · test · bench · compile · doc — no prettier/eslint/jest.
Deno.serveDeno.serve((req) => new Response()) — web-standard HTTP.
web-firstprefer fetch/Request/ReadableStream/crypto.subtle; Deno.* for the rest.
depsdeno add jsr:@std/http → deno.json + deno.lock; deno install/ci.
compiledeno compile → a single self-contained executable.
Deno 2Node/npm compatible — run existing package.json projects.
unstableDeno.openKv (--unstable-kv), FFI Deno.dlopen (--allow-ffi).
no __dirnameuse import.meta.dirname / import.meta.url / import.meta.main.