oven-sh/bun
Three main pipelines dominate. (1) Source → runtime: the JSC module loader asks `Bun__transpile*` hooks in `jsc_hooks.rs`, which resolve through `bun_resolver`, parse with `bun_js_parser`, print with `bun_js_printer`, and hand a `ResolvedSource` back to JSC; results are cached in a `RuntimeTranspilerStore` and an arena that is reset between graphs. (2) Package manifests → lockfile → disk: `install_with_manager` loads the lockfile, resolves dependencies via the registry client and task queue, runs a security scan, extracts tarballs, links binaries, then runs lifecycle scripts and saves the lockfile. (3) Bundling: `BundleV2` owns a `Graph` of parse tasks fanned out to worker threads, then `LinkerContext` performs tree-shaking, chunking, and sourcemap emission. Cross-thread movement is explicit: `ConcurrentTask`/`DeferredTaskQueue` marshal work onto the JS thread, and the HTTP client runs on its own `HTTPThread`.
- Module loading is split across the crate boundary on purpose: `ModuleLoader` and `FetchFlags` live in `bun_jsc`, while the actual `transpile_source_code`/`fetch_builtin_module` bodies and the `Bun__transpile*`/`Bun__resolve*` C++ entry points live in `bun_runtime::jsc_hooks` and are reached through link-time `extern "Rust"` declarations.
- The transpiler arena is owned by `ModuleLoader::transpile_source_code_arena` and reset between module graphs via `ModuleLoader::reset_arena`, which takes `&mut VirtualMachine` rather than `&mut self` because `ModuleLoader` is a value field of the VM and taking both would alias.
- Entry-point evaluation flows `vm.load_entry_point(entry)` → a JSC internal promise; a rejected promise is routed to `vm.uncaught_exception` with an `is_rejection` flag derived from `entry_point_result.evaluated_as_cjs`, so a CJS entry's top-level throw is reported as `uncaughtException` and an ESM entry's as `unhandledRejection`, matching Node.
- Environment data enters through `bun_dotenv::Loader` wired onto the transpiler, is published to the HTTP client via `bun_http::async_http::load_env`, and on Windows the UTF-16 OS environment block is converted to WTF-8 in `main()` before anything reads `process.env`.
- CLI configuration merges three inputs — argv (parsed by `Arguments::parse` into a `ContextData`), the `BUN_OPTIONS` env var (spliced into argv), and `bunfig.toml` parsed by `src/bunfig/bunfig.rs` — with `ctx.args`/`ctx.debug`/`ctx.runtime_options` as the state owner passed down to every command.
- Registry credentials flow from two sources into one `api::NpmRegistry` value: `.npmrc`-style `_authToken` segments parsed in `src/install/npm.rs`, and `[install.scopes]` entries in bunfig where explicit `username`/`password`/`token` keys replace any credentials embedded in the URL as a set.
- `install_with_manager` is the state machine for installs: prefetch DNS for the registry, load the lockfile from cwd, reconcile config version, diff the root package, enqueue dependency resolution, run tasks, then save the lockfile — with a `mark_loaded_packages()` checkpoint so packages appended by manifest fetches are distinguishable from lockfile pins.
- The security scanner runs user-supplied scanning code out-of-process and talks to it over two dedicated file descriptors — fd 3 for the child's JSON result and fd 4 for the parent's package list, read to EOF — rather than stdin/stdout, so scanner console output can't corrupt the protocol.
- Lifecycle scripts are spawned through `bun_spawn` from `src/install/lifecycle_script_runner.rs`, which is deliberately placed in the lower `bun_install` crate so `bun run` and package-install script execution share one implementation (`RunCommand::replace_package_manager_run` is a thin re-export).
- Bundling state is owned by `BundleV2`, which holds a `Graph`, a `PathToSourceIndexMap`, `ParseTask`s, and an optional second `ssr_transpiler` used for the client half of a Server Components build; linking and chunking happen in the separate `LinkerContext`.
- The dev server keeps every build artifact in memory behind an `IncrementalGraph` with the stated invariant that editing a file must rebundle exactly that file, and exposes a `memory_cost_detailed` breakdown so that in-memory retention is measurable.
- Cross-thread data movement is centralized in `src/event_loop/`: `ConcurrentTask` and `DeferredTaskQueue` enqueue onto the JS thread, `AnyEventLoop` abstracts over the uWS loop on POSIX and libuv on Windows, and `MiniEventLoop`/`SpawnSyncEventLoop` serve non-JS contexts like the package manager.
- Outbound HTTP is a separate subsystem with its own thread and protocol clients — `HTTPThread.rs`, `H2Client.rs` (HTTP/2 over lshpack), `H3Client.rs` (HTTP/3 over lsquic), plus decompression and certificate-info paths — and `fetch` opts into h2/h3 via process-global atomics set from CLI flags.
- S3 requests are signed in the `bun_s3_signing` crate, which owns credentials, ACL, storage class, and multipart options as pure config with no JSC dependency, and the runtime's `S3Client`/`S3File` re-export it — keeping signing testable below the JS tier.