← All unpacks
CodeVetter · Repo Unpack comparison

bun vs node

bun scanned at bf80d21 (2026-09-22) · node at 976a36a (2026-09-22) · codevetter codevetter 1.12.0

Bun's Zig/JavaScriptCore all-in-one toolchain vs Node's V8/libuv runtime plus separate package tooling.

oven-sh/bunnodejs/node
Files scanned39963999
Size37.9 MB43.3 MB
Primary source rootsrc/src/
Top languageJavaScript (7870 files)JavaScript (23278 files)
Packagenull v0.0.0null v—
Structural health5.3/10 avg, 89 hotspots5.4/10 avg, 94 hotspots
Test signalmissingmissing

Architectures

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.

node

This is the Node.js runtime itself at v26.10.0 — a C++/V8 host (src/, ~495 files) wrapping a JavaScript standard library (lib/, ~429 files) that is compiled into a V8 startup snapshot at build time. Beyond upstream-familiar surface, this tree carries several large experimental subsystems wired through the same plumbing: a `node:vfs` virtual file system that intercepts `node:fs` and the module loaders at reserved mount points under `os.devNull/vfs/<id>`, a `node:ffi` libffi-backed foreign function interface gated by a `kFFI` permission scope, a `node:dtls` endpoint/session stack, a `node --experimental-bench` benchmark runner mirroring the test runner, and a vendored Rust crate set (`deps/crates`, temporal_rs + ICU) linked as a staticlib. The audience is Node core collaborators; the distinctive engineering property is that every new capability is a triple — a CLI option in `src/node_options.cc`, a `setupX()` in `pre_execution.js` that calls `BuiltinModule.allowRequireByUsers()`, and an internal binding registered in `src/node_binding.h`.

System maps

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`).

node

Execution begins in `src/node_main.cc` (`main`/`wmain`) which calls `node::Start`, which after SEA argv fixup loads the V8 startup snapshot and runs a `NodeMainInstance`. C++ then picks exactly one main script from `lib/internal/main/` via a linear dispatch in `src/node.cc`; that script calls into `lib/internal/process/pre_execution.js` to configure the realm before user code. The JS layer talks to C++ only through `internalBinding()`, whose registry is the `NODE_BUILTIN_*_BINDINGS` macro list in `src/node_binding.h`. Build is GYP/Make (`configure.py` → `node.gyp` → `Makefile`) with a secondary GN path, plus Cargo for `deps/crates`. There is no deployment target in the usual sense: the artifact is the `node` binary, optionally repackaged as a single executable application by `src/node_sea.cc`.

Repository structure

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

node

  • test/ — 863 files
  • deps/ — 863 files
  • benchmark/ — 637 files
  • src/ — 495 files
  • lib/ — 429 files
  • tools/ — 391 files
  • doc/ — 162 files
  • .github/ — 60 files