This page describes Bun's build infrastructure: the TypeScript-based Ninja build orchestration, the CI/CD pipeline on Buildkite, and the platform bootstrap scripts used to provision build and test machines. It covers how the build is configured, how C++, Rust, and Zig sources are compiled and linked, and how the CI pipeline parallelizes work across platforms.
For Zig-specific compilation details, see Zig Build System. For the code generation scripts that produce C++/Rust bindings from TypeScript definitions, see Code Generation Pipeline. For WebKit/JSC integration specifics, see WebKit and JavaScriptCore Integration. For CI pipeline details, see CI/CD Pipeline. For bootstrap and machine provisioning details, see Platform Support and Bootstrap. For debugger and IDE setup, see Debugger and IDE Integration.
Bun's build system replaced a CMake-based setup with a TypeScript program that emits a build.ninja file and then invokes ninja to execute it. The build scripts live under scripts/build/ and are the sole source of truth for compilation flags, dependency handling, and artifact layout.
Build System Flow
Sources: scripts/build.ts1-60 scripts/build/bun.ts1-50 scripts/build/configure.ts1-50
The central type throughout the build system is the Config interface defined in scripts/build/config.ts resolved by resolveConfig(). Every build function receives this struct — no global state, no option object threading.
| Field Group | Key Fields | Purpose |
|---|---|---|
| Target platform | os, arch, abi | linux/darwin/windows/freebsd, x64/aarch64, gnu/musl/android |
| Derived booleans | linux, darwin, windows, unix, x64, arm64 | Convenience predicates computed once |
| Build config | buildType, debug, release, mode | Debug/Release/RelWithDebInfo, cpp-only/rust-only/link-only/full |
| Features | lto, crossLangLto, asan, baseline, canary, pgoGenerate, pgoUse | Optional build features |
| Toolchain paths | cc, cxx, ar, ld, ranlib | Resolved absolute paths to compiler tools |
| Version pins | webkitVersion, nodejsVersion, nodejsAbiVersion | Dependency version constants |
| Paths | cwd, buildDir, codegenDir, cacheDir, vendorDir | Directory layout |
| Host | host.os, host.arch, host.rustTriple | What machine is running the build (vs. target) |
Sources: scripts/build/config.ts73-250
resolveConfig() also resolves the macOS SDK path via resolveMacosSdkPath(), clang resource directory, and cross-compilation sysroot. All of these are embedded as absolute paths into Config.
The BuildMode type controls what a single bun run build invocation produces:
| Mode | What it does | CI use |
|---|---|---|
"full" | C++ compile → Rust compile → link | Local dev |
"cpp-only" | C++ compile → libbun.a only | CI upstream step |
"rust-only" | Codegen + cargo build → libbun_rust.a only | CI upstream step (parallel with cpp-only) |
"link-only" | Downloads artifacts from sibling steps, links binary | CI downstream step |
In CI, cpp-only and rust-only run in parallel on separate agents. link-only depends on both.
Named profiles are defined in the build orchestration. Profiles set a BuildType and a combination of feature flags. Examples:
| Profile name | BuildType | Notable flags |
|---|---|---|
debug | Debug | No LTO, assertions on, logs on |
release | Release | LTO on, stripped |
asan | RelWithDebInfo | asan=true, no strip |
ci-cpp-only | Release | mode="cpp-only" |
ci-rust-only | Release | mode="rust-only" |
ci-link-only | Release | mode="link-only" |
Sources: scripts/build/config.ts23-26 .buildkite/ci.mjs40-56
All compiler and linker flags are defined as flat tables in scripts/build/flags.ts Each entry has three fields:
flag: the flag string(s), or a function (cfg: Config) => string | string[]when: optional predicate; omitted means always applydesc: human-readable description used by --explain-flagsFlag categories:
| Export | Purpose |
|---|---|
cpuTargetFlags | -march/-mcpu/-mtune — per-OS/arch target |
globalFlags | Applied to all C/C++ sources and forwarded to deps |
linkerFlags | Passed at link time only |
CPU target examples:
| When | Flag |
|---|---|
darwin && arm64 | -mcpu=apple-m1 |
linux && arm64 | -march=armv8-a+crc -mtune=ampere1 |
x64 && baseline | -march=nehalem (no AVX) |
x64 && !baseline | -march=haswell (AVX2) |
Sources: scripts/build/flags.ts49-80 scripts/build/flags.ts88-164
Dependencies are declared using a Dependency interface in scripts/build/source.ts Each dep specifies a source and a build spec.
BuildSpec variants:
| Kind | What happens | Examples |
|---|---|---|
direct | Sources listed explicitly; each gets a cc/cxx ninja edge; .os go into bun's link | zlib, zstd, boringssl, mimalloc, libarchive |
nested-cmake | Dep's own CMake configure + build run as ninja edges | lolhtml |
cargo | cargo build invoked as a ninja edge | lolhtml Rust parts |
prebuilt | Tarball downloaded and extracted; no build | WebKit/JSC, nodejs-headers |
Dependency Resolution Flow
Sources: scripts/build/source.ts1-42 scripts/build/bun.ts32-41
The Rust build is described in scripts/build/rust.ts The entire Rust workspace is compiled via cargo build -p bun_bin into a single libbun_rust.a static archive. Ninja emits one edge for this; cargo's own incremental compilation handles per-file tracking.
Key functions:
| Function | Purpose |
|---|---|
rustTarget(cfg) | Maps Config → Rust target triple (e.g. x86_64-unknown-linux-gnu) |
emitRust(n, cfg) | Emits the cargo ninja edge and returns the path to libbun_rust.a |
Most targets (linux, musl, android, freebsd, darwin, windows) can be cross-compiled from a Linux host. The rust-toolchain.toml at rust-toolchain.toml1-12 pins the nightly channel.
Sources: scripts/build/rust.ts1-39 rust-toolchain.toml1-12
The Buildkite pipeline is generated dynamically by .buildkite/ci.mjs The script runs at pipeline-upload time and emits YAML steps based on the buildPlatforms and testPlatforms arrays.
Build Platform Overview
Sources: .buildkite/ci.mjs132-176 .buildkite/ci.mjs112-123
macOS, Windows, FreeBSD, and Android are all cross-compiled from Linux EC2 instances. There is no native macOS or Windows build lane:
| Target OS | Toolchain | Sysroot |
|---|---|---|
| macOS | clang --target + ld64.lld | Apple SDK via macos-sdk.ts |
| Windows | clang-cl --target + lld-link | xwin MSVC/SDK sysroot |
Sources: .buildkite/ci.mjs133-165 scripts/build/flags.ts88-111
Bootstrap scripts provision fresh machines with all build dependencies. They are versioned with a comment at the top; incrementing the version triggers a new image build.
scripts/bootstrap.sh (Linux / macOS)Installs:
Sources: scripts/bootstrap.sh1-32 scripts/bootstrap.sh278-308
scripts/bootstrap.ps1 (Windows)Uses Scoop as the package manager (ARM64-native). Installs:
rustup-init.exesde.exe) for baseline CPU verificationSources: scripts/bootstrap.ps11-31 scripts/bootstrap.ps1163-200
scripts/machine.mjs handles cloud machine lifecycle for both AWS EC2 (Linux/macOS tests) and Azure VMs (Windows tests). It supports create-image, publish-image, and instance management actions.
Sources: scripts/machine.mjs1-45 scripts/machine.mjs47-119 .buildkite/ci.mjs112-123
| File | Key export(s) |
|---|---|
scripts/build/config.ts | Config, Host, resolveConfig() |
scripts/build/flags.ts | cpuTargetFlags, globalFlags, linkerFlags |
scripts/build/bun.ts | emitBun(), systemLibs() |
scripts/build/rust.ts | emitRust(), rustTarget() |
scripts/build/source.ts | resolveDep(), Dependency |
.buildkite/ci.mjs | Pipeline generator: buildPlatforms, testPlatforms |
scripts/runner.node.mjs | Test shard runner |
scripts/bootstrap.sh | Linux/macOS machine provisioning |
scripts/bootstrap.ps1 | Windows machine provisioning |
scripts/machine.mjs | Cloud VM lifecycle management |
rust-toolchain.toml | Pinned nightly Rust toolchain |
Sources: scripts/build/bun.ts157-164 scripts/build/config.ts73-115 scripts/build/rust.ts1-39
Refresh this wiki
This wiki was recently refreshed. Please wait 7 days to refresh again.