CodeVetter
← All unpacks
CodeVetter · Repo Unpack evidence

denoland/deno

Scanned commit 461f32ec61 dated 2026-09-21 — last upstream commit. Generated by codevetter 1.12.0 on 2026-09-22.

github.com/denoland/deno ↗ · 3997 files · 37.1 MB · scan capped

Deno [![Twitter badge][]][Twitter link] [![Bluesky badge][]][Bluesky link] [![Discord badge][]][Discord link] [![YouTube badge][]][YouTube link] Deno (/ˈdiːnoʊ/, pronounced dee-no) is a JavaScript, TypeScript, and WebAssembly runtime with secure defaults and a

Deep analysis by claude-opus-5 via the claude CLI on 2026-09-22 (495s) — every claim below links to its cited source files.

Overview

This is the Deno runtime monorepo — a Rust workspace (~80 crates) that builds a JavaScript/TypeScript/WebAssembly runtime on V8 and Tokio, plus the `deno` CLI that wraps it with a package manager, type checker, formatter, linter, test runner, LSP server, and single-file-binary compiler. The distinctive shape is three layers: `libs/` holds vendored foundational crates (notably `deno_core` v0.412.0 at `libs/core`, the op2 proc-macro at `libs/ops`, and a hand-rolled zero-allocation flag parser at `libs/cli_parser` that replaced clap with `const` command tables), `ext/` holds 32 self-contained extension crates that expose native ops to JS, and `runtime/`+`cli/` assemble them into the shipped binary. Everything user code touches passes through a capability permission system (`runtime/permissions/lib.rs`, ~11.7k lines) that gates read/write/net/env/sys/run/ffi/import, and the CLI is built around a lazily-memoised dependency-injection container (`CliFactory`) so that `deno fmt` never pays for the npm resolver. It targets JS/TS application developers and, increasingly, Node.js users — a large fraction of `ext/node` exists purely for npm/Node compatibility.

System map

The binary entry is a nine-line `cli/main.rs` that delegates to `deno::main()` in `cli/lib.rs`, which parses flags, initialises V8, and dispatches a `DenoSubcommand` to a handler under `cli/tools/`. Shared services are constructed lazily through `CliFactory`, a container of `Deferred<T>` once-cells covering caches, resolvers, the file fetcher, npm installer, type checker, and permission container. The JS runtime is assembled in `runtime/worker.rs::common_extensions`, which registers ~35 extension crates from `ext/` in a strict, snapshot-sensitive order; a V8 startup snapshot is baked at build time by `cli/snapshot/build.rs`. Storage is the DENO_DIR: SQLite caches (`cli/cache/caches.rs`) for dep analysis, type checking, code cache, fast-check, and lint/fmt incremental state, plus an HTTP cache and npm package cache. Builds run through `cargo`/`./x`, CI is generated TypeScript (`.github/workflows/ci.ts` → `ci.generated.yml`), and the deployment shape is a single statically-linked executable distributed per-platform.

All 15 system map claims →

Feature catalog

The CLI surface is unusually broad for a runtime: beyond `run`/`eval`/`repl`/`serve`, it ships a full npm/JSR package manager (`add`, `remove`, `install`, `outdated`, `why`, `audit`, `link`, `pack`, `publish`), a TypeScript type checker, dprint-backed formatter, deno_lint-backed linter with a JS plugin API, a test runner with leak sanitizers and coverage, a benchmarking harness, a documentation generator, a Jupyter kernel, an LSP server, a single-binary compiler, and a Deno Deploy client that bootstraps itself from JSR at runtime. Extensions in `ext/` expose the user-visible Web and Node APIs: fetch, WebSocket, WebGPU, Web Crypto, KV, Cron, FFI, N-API, and a 119-file Node polyfill tree. `deno serve` adds multi-process HTTP serving with `--parallel`, and a tunnel client can expose a local process through Deno's cluster endpoint.

All 15 feature catalog claims →

Data flow

Input boundaries are argv (parsed into `Flags` by the const-table parser), environment variables and `.env` files, config files (`deno.json`/`package.json`) discovered through the workspace factory, and remote sources fetched over HTTP from JSR and npm registries. `CliFactory` owns the service graph; `ModuleGraphBuilder` builds a `deno_graph::ModuleGraph` from roots, `TypeChecker` optionally validates it against a TSC-backed cache, and `CliEmitter` transpiles TypeScript to JavaScript. At runtime, `CliModuleLoader::load` serves module source out of the prepared graph (or delegates to JS load hooks, or to an eszip), and V8 executes it. Every side-effecting op re-enters Rust through `PermissionsContainer`, which is the single state owner for capability decisions. Output boundaries are stdout/stderr (via `deno_print`/`DrawThread`), the DENO_DIR SQLite and HTTP caches, the lockfile, OpenTelemetry exporters, and for `compile`, a written executable.

All 15 data flow claims →

Behavior traces

Three flows dominate. Startup: `main()` → panic hook/logging/fd-limit → optional control-socket handshake → `resolve_flags_and_init` → `init_v8` → `run_subcommand`. Primary action (`deno run`): `tools::run::run_script` → `CliFactory` service warm-up → main-module resolution → npm install → `create_cli_main_worker_factory_with_roots` → `create_main_worker_with_unconfigured_runtime` → `CliMainWorker::run`. Persistence (`deno compile`): `compile_inner` → module graph creation → `DenoCompileBinaryWriter::write_bin` → VFS build → `MAGIC_BYTES`-framed binary written to disk. A fourth path worth knowing is the pre-warmed-runtime handshake on Unix, where `DENO_UNSTABLE_CONTROL_SOCK` lets a parent hand this process an already-initialised `UnconfiguredRuntime` and a replacement argv.

All 15 behavior traces claims →

Testing signals

Testing is Rust-driven but mostly JS/JSONC-authored. Five separate cargo test crates each use `file_test_runner` with `harness = false` and a custom `main()`: `specs_tests` (CLI integration via `__test__.jsonc`), `unit_tests` (`tests/unit/*_test.ts`), `unit_node_tests`, `node_compat_tests`, and `integration_tests` (28 Rust files). Web Platform Tests run from a git submodule under `tests/wpt`, and results are uploaded to wpt.fyi and S3 from CI. Each runner computes a content hash of its inputs (`check_ci_hash`) and skips entirely when nothing changed. Coverage gaps are structural rather than accidental: the spec suite exercises the CLI as a black box, so internal Rust units like `CliFactory` wiring, the tunnel client, and `standalone/binary.rs` framing have little direct unit coverage.

All 15 testing signals claims →

Risk map

The blast radius concentrates in three places: the permission system (an 11.7k-line file that every capability check funnels through), the extension ordering list in `runtime/worker.rs` (silently snapshot-coupled across four files), and the many `unsafe { std::env::set_var(...) }` calls in startup that are only sound because they run before any thread is spawned. Security-sensitive paths include FFI `dlopen`, subprocess spawn with LD_PRELOAD-style env filtering, the permission broker's IPC socket, the Deno Deploy keyring token, the runtime-fetched deploy CLI executed with `allow_all`, and the `node` shim that mutates the process `PATH`. Several performance-motivated lazy-loading decisions (lazy node polyfills, hoisted `registerDeclarativeServer` guard) are fragile in the sense that they encode non-obvious invariants in comments rather than tests.

All 16 risk map claims →

Extension points

New native capability is added as an `ext/<name>` crate using `deno_core::extension!` (ops + esm + lazy_loaded_esm), registered into the ordered list in `runtime/worker.rs::common_extensions`, and exposed to JS from the extension's own `.js`/`.ts` files. New CLI surface is added by extending the `const` tables in `libs/cli_parser/src/defs.rs`, adding a `DenoSubcommand` variant in `flags.rs`, a conversion in `convert.rs`, an arm in `run_subcommand`, and a handler module under `cli/tools/`. New shared services are added as `Deferred<T>` fields on `CliFactoryServices` with an accessor method. The `deno task` shell has its own `ShellCommand` registry, the module loader has a JS-level load-hook registry, and the developer tooling itself is extensible via `tools/x.ts`'s command record and `.claude/skills/`.

All 15 extension points claims →

Contributor handoff

Read `CLAUDE.md`, `tools/x.ts`, `cli/lib.rs`, and `cli/factory.rs` first — those four give you the command surface, the dispatch table, and the service graph. Use `./x` rather than raw cargo: `./x check` for fast feedback, `./x build` for a binary, `./x test-spec <filter>` for integration tests (a filter is mandatory and the runner will panic without one under Claude Code), and `./x verify` (fmt + lint-js) before committing. The repo's conventions are enforced mechanically: dprint formatting, a copyright-header check, generated-workflow freshness, and a clippy `disallowed_methods` list that is why you see `#[allow(clippy::disallowed_methods, reason = "…")]` sprinkled through startup code. Keep diffs minimal and avoid drive-by changes — the CLAUDE.md git workflow says so explicitly, and PRs are squash-merged so never force-push.

All 15 contributor handoff claims →

Languages

LanguageFilesShare of source
TypeScript357355%
JSON2016docs/config
JavaScript171226%
Rust105216%
TOML1522%
Markdown129docs/config
CSS28docs/config
YAML27docs/config

Start reading here

Probable source entrypoint: Cargo.toml — inferred from the directory tree and manifest, not the upstream docs.

Source roots

libs/ (801 files) ext/ (752 files) cli/ (517 files)

Source layout — cli/

PathFiles
cli/args/3
cli/benches/1
cli/cache/9
cli/examples/1
cli/js/9
cli/lib/25
cli/lsp/38
cli/ops/6
cli/rt/12
cli/rt_desktop/3
cli/schemas/10
cli/snapshot/5
cli/standalone/4
cli/tools/98

Repository structure

Top-level pathFiles
tests/1720
libs/801
ext/752
cli/517
runtime/74
tools/69
.github/32
doc/7

Docs found: CLAUDE.mdLICENSE.mdREADME.md

Package

Cargo.toml — , 0 declared dependencies.

CI & config entrypoints

Structural health signals

Average score 5.5/10 across 96 analyzed source files; 85 hotspots surfaced.

These are deterministic review leads — size, churn, and structural signals — not proof of a bug in this project.

Recent history