← All unpacks
CodeVetter · Repo Unpack comparison

deno vs bun

deno scanned at 461f32e (2026-09-21) · bun at bf80d21 (2026-09-22) · codevetter codevetter 1.12.0

Two post-Node runtimes — Deno leans on V8 and Rust crates, Bun on JavaScriptCore and Zig.

denoland/denooven-sh/bun
Files scanned39973996
Size37.1 MB37.9 MB
Primary source rootlibs/src/
Top languageTypeScript (3573 files)JavaScript (7870 files)
Packagenull v—null v0.0.0
Structural health5.5/10 avg, 85 hotspots5.3/10 avg, 89 hotspots
Test signalmissingmissing

Architectures

deno

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.

bun

Bun is an all-in-one JavaScript/TypeScript runtime, bundler, transpiler, test runner, and npm-compatible package manager built on WebKit's JavaScriptCore and shipped as a single native binary. The codebase at this commit is a ~200-crate Rust Cargo workspace (`src/`) linked against a large C++ JSC bindings layer (`src/jsc/bindings/`, 407 files), ~15 vendored native dependencies, and a TypeScript layer (`src/js/`) that is bundled at build time into the binary as built-in modules like `node:fs` and `bun:ffi`. Everything routes through one process entry (`src/runtime/bin_entry/mod.rs::main`) into a single subcommand dispatch table (`src/runtime/cli/mod.rs`) covering 34 command tags — `run`, `install`, `test`, `build`, `pm`, `x`, `publish`, `audit`, and more. What's distinctive is the obsessive cold-start engineering (`#[cold]` on every non-`bun run` subcommand body, symbol ordering, mimalloc wired into ICU/libuv/BoringSSL before anything allocates) and a review culture encoded as machine-checked policy: `clippy.toml` bans `std::fs`, `mordant.toml` ratchets Rust lints against a baseline, and `REVIEW.md` distills ~2,500 merged PRs into merge-blocking rules.

System maps

deno

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.

bun

One native executable with a Rust core, a C++ JSC binding layer, and a build-time-bundled TypeScript module layer. `src/runtime/bin_entry/mod.rs` is the C-ABI `main`; it initializes the crash handler, allocator, stdio, and stack limits, then hands off to `cli::Cli::start()` which decodes a `Tag` and dispatches to one of 34 subcommand bodies. Storage is not a database — it's the lockfile (`bun.lock` text / `bun.lockb` binary under `src/install/lockfile/`), the global package cache, and the standalone-executable graph appended to the binary itself. Builds go through `scripts/build.ts` → CMake/ninja + `cargo` per-crate rlibs; CI is a generated Buildkite pipeline (`.buildkite/ci.ts`) plus 25 GitHub Actions workflows. Deployment shape is a downloadable binary plus npm packages, Docker images (`dockerhub/`), and a VS Code extension (`packages/bun-vscode`).

Repository structure

deno

  • tests/ — 1720 files
  • libs/ — 801 files
  • ext/ — 752 files
  • cli/ — 517 files
  • runtime/ — 74 files
  • tools/ — 69 files
  • .github/ — 32 files
  • doc/ — 7 files

bun

  • src/ — 1353 files
  • test/ — 1352 files
  • bench/ — 374 files
  • docs/ — 358 files
  • packages/ — 312 files
  • scripts/ — 80 files
  • .github/ — 45 files
  • patches/ — 30 files