Configuring a development environment for Bun can take 10-30 minutes depending on your internet connection and computer speed. You will need ~10GB of free disk space for the repository and build artifacts.
If you are using Windows, please refer to this guide
Using Nix (Alternative)
A Nix flake is provided as an alternative to manual dependency installation:
nix develop
# or explicitly use the pure shell
# nix develop .#pure
export CMAKE_SYSTEM_PROCESSOR=$(uname -m)
bun bdThis provides all dependencies in an isolated, reproducible environment without requiring sudo.
Install Dependencies (Manual)
Using your system's package manager, install Bun's dependencies:
$ brew install automake cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rust ruby sccache$ sudo apt install curl wget lsb-release software-properties-common cargo cmake git golang libtool ninja-build pkg-config rustc ruby-full xz-utils$ sudo pacman -S base-devel cmake git go libiconv libtool make ninja pkg-config python rust sed unzip ruby$ sudo dnf install cargo clang19 llvm19 lld19 cmake git golang libtool ninja-build pkg-config rustc ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'$ sudo zypper install go cmake ninja automake git icu rustup && rustup toolchain install stableNote: The Zig compiler is automatically installed and updated by the build scripts. Manual installation is not required.
Before starting, you will need to already have a release build of Bun installed, as we use our bundler to transpile and minify our code, as well as for code generation scripts.
$ curl -fsSL https://bun.com/install | bash$ npm install -g bun$ brew tap oven-sh/bun
$ brew install bunOptional: Install sccache
sccache is used to cache compilation artifacts, significantly speeding up builds. It must be installed with S3 support:
# For macOS
$ brew install sccache
# For Linux. Note that the version in your package manager may not have S3 support.
$ cargo install sccache --features=s3This will install sccache with S3 support. Our build scripts will automatically detect and use sccache with our shared S3 cache. Note: Not all versions of sccache are compiled with S3 support, hence we recommend installing it via cargo.
Registering AWS Credentials for sccache (Core Developers Only)
Core developers have write access to the shared S3 cache. To enable write access, you must log in with AWS credentials. The easiest way to do this is to use the aws CLI and invoke aws configure to provide your AWS security info.
The cmake scripts should automatically detect your AWS credentials from the environment or the ~/.aws/credentials file.
Logging in to the `aws` CLI
1. Install the AWS CLI by following [the official guide](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html).
2. Log in to your AWS account console. A team member should provide you with your credentials.
3. Click your name in the top right > Security credentials.
4. Scroll to "Access keys" and create a new access key.
5. Run `aws configure` in your terminal and provide the access key ID and secret access key when prompted.
Common Issues You May Encounter
- To confirm that the cache is being used, you can use the `sccache --show-stats` command right after a build. This will expose very useful statistics, including cache hits/misses.
- If you have multiple AWS profiles configured, ensure that the correct profile is set in the `AWS_PROFILE` environment variable.
- `sccache` follows a server-client model. If you run into weird issues where `sccache` refuses to use S3, even though you have AWS credentials configured, try killing any running `sccache` servers with `sccache --stop-server` and then re-running the build.
Install LLVM
Bun requires LLVM 19 (clang is part of LLVM). This version requirement is to match WebKit (precompiled), as mismatching versions will cause memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
$ brew install llvm@19$ # LLVM has an automatic installation script that is compatible with all versions of Ubuntu
$ wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 19 all$ sudo pacman -S llvm clang lld$ sudo dnf install llvm clang lld-devel$ sudo zypper install clang19 lld19 llvm19If none of the above solutions apply, you will have to install it manually.
Make sure Clang/LLVM 19 is in your path:
$ which clang-19If not, run this to manually add it:
# use fish_add_path if you're using fish
# use path+="$(brew --prefix llvm@19)/bin" if you are using zsh
$ export PATH="$(brew --prefix llvm@19)/bin:$PATH"# use fish_add_path if you're using fish
$ export PATH="$PATH:/usr/lib/llvm19/bin"Building Bun
After cloning the repository, run the following command to build. This may take a while as it will clone submodules and build dependencies.
bun run buildThe binary will be located at ./build/debug/bun-debug. It is recommended to add this to your $PATH. To verify the build worked, let's print the version number on the development build of Bun.
$ build/debug/bun-debug --version
x.y.z_debugVSCode
VSCode is the recommended IDE for working on Bun, as it has been configured. Once opening, you can run Extensions: Show Recommended Extensions to install the recommended extensions for Zig and C++. ZLS is automatically configured.
If you use a different editor, make sure that you tell ZLS to use the automatically installed Zig compiler, which is located at ./vendor/zig/zig.exe. The filename is zig.exe so that it works as expected on Windows, but it still works on macOS/Linux (it just has a surprising file extension).
We recommend adding ./build/debug to your $PATH so that you can run bun-debug in your terminal:
bun-debugRunning debug builds
The bd package.json script compiles and runs a debug build of Bun, only printing the output of the build process if it fails.
bun bd <args>
bun bd test foo.test.ts
bun bd ./foo.tsBun generally takes about 2.5 minutes to compile a debug build when there are Zig changes. If your development workflow is "change one line, save, rebuild", you will spend too much time waiting for the build to finish. Instead:
- Batch up your changes
- Ensure zls is running with incremental watching for LSP errors (if you use VSCode and install Zig and run
bun run buildonce to download Zig, this should just work) - Prefer using the debugger ("CodeLLDB" in VSCode) to step through the code.
- Use debug logs.
BUN_DEBUG_<scope>=1will enable debug logging for the correspondingOutput.scoped(.<scope>, .hidden)logs. You can also setBUN_DEBUG_QUIET_LOGS=1to disable all debug logging that isn't explicitly enabled. To dump debug logs into a file,BUN_DEBUG=<path-to-file>.log. Debug logs are aggressively removed in release builds. - src/js/**.ts changes are pretty much instant to rebuild. C++ changes are a bit slower, but still much faster than the Zig code (Zig is one compilation unit, C++ is many).
Code generation scripts
Several code generation scripts are used during Bun's build process. These are run automatically when changes are made to certain files.
In particular, these are:
./src/codegen/generate-jssink.ts-- Generatesbuild/debug/codegen/JSSink.cpp,build/debug/codegen/JSSink.hwhich implement various classes for interfacing withReadableStream. This is internally howFileSink,ArrayBufferSink,"type": "direct"streams and other code related to streams works../src/codegen/generate-classes.ts-- Generatesbuild/debug/codegen/ZigGeneratedClasses*, which generates Zig & C++ bindings for JavaScriptCore classes implemented in Zig. In**/*.classes.tsfiles, we define the interfaces for various classes, methods, prototypes, getters/setters etc which the code generator reads to generate boilerplate code implementing the JavaScript objects in C++ and wiring them up to Zig./src/codegen/cppbind.ts-- Generates automatic Zig bindings for C++ functions marked with[[ZIG_EXPORT]]attributes../src/codegen/bundle-modules.ts-- Bundles built-in modules likenode:fs,bun:ffiinto files we can include in the final binary. In development, these can be reloaded without rebuilding Zig (you still need to runbun run build, but it re-reads the transpiled files from disk afterwards). In release builds, these are embedded into the binary../src/codegen/bundle-functions.ts-- Bundles globally-accessible functions implemented in JavaScript/TypeScript likeReadableStream,WritableStream, and a handful more. These are used similarly to the builtin modules, but the output more closely aligns with what WebKit/Safari does for Safari's built-in functions so that we can copy-paste the implementations from WebKit as a starting point.
Modifying ESM modules
Certain modules like node:fs, node:stream, bun:sqlite, and ws are implemented in JavaScript. These live in src/js/{node,bun,thirdparty} files and are pre-bundled using Bun.
Release build
To compile a release build of Bun, run:
bun run build:releaseThe binary will be located at ./build/release/bun and ./build/release/bun-profile.
Download release build from pull requests
To save you time spent building a release build locally, we provide a way to run release builds from pull requests. This is useful for manually testing changes in a release build before they are merged.
To run a release build from a pull request, you can use the bun-pr npm package:
bunx bun-pr <pr-number>
bunx bun-pr <branch-name>
bunx bun-pr "https://github.com/oven-sh/bun/pull/1234566"
bunx bun-pr --asan <pr-number> # Linux x64 onlyThis will download the release build from the pull request and add it to $PATH as bun-${pr-number}. You can then run the build with bun-${pr-number}.
bun-1234566 --versionThis works by downloading the release build from the GitHub Actions artifacts on the linked pull request. You may need the gh CLI installed to authenticate with GitHub.
AddressSanitizer
AddressSanitizer helps find memory issues, and is enabled by default in debug builds of Bun on Linux and macOS. This includes the Zig code and all dependencies. It makes the Zig code take about 2x longer to build, if that's stopping you from being productive you can disable it by setting -Denable_asan=$<IF:$<BOOL:${ENABLE_ASAN}>,true,false> to -Denable_asan=false in the cmake/targets/BuildBun.cmake file, but generally we recommend batching your changes up between builds.
To build a release build with Address Sanitizer, run:
bun run build:release:asanIn CI, we run our test suite with at least one target that is built with Address Sanitizer.
Building WebKit locally + Debug mode of JSC
WebKit is not cloned by default (to save time and disk space). To clone and build WebKit locally, run:
# Clone WebKit into ./vendor/WebKit
$ git clone https://github.com/oven-sh/WebKit vendor/WebKit
# Check out the commit hash specified in `set(WEBKIT_VERSION <commit_hash>)` in cmake/tools/SetupWebKit.cmake
$ git -C vendor/WebKit checkout <commit_hash>
# Make a debug build of JSC. This will output build artifacts in ./vendor/WebKit/WebKitBuild/Debug
# Optionally, you can use `bun run jsc:build` for a release build
bun run jsc:build:debug && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
# After an initial run of `make jsc-debug`, you can rebuild JSC with:
$ cmake --build vendor/WebKit/WebKitBuild/Debug --target jsc && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
# Build bun with the local JSC build
bun run build:localUsing bun run build:local will build Bun in the ./build/debug-local directory (instead of ./build/debug), you'll have to change a couple of places to use this new directory:
- The first line in
src/js/builtins.d.ts - The
CompilationDatabaseline in.clangdconfig should beCompilationDatabase: build/debug-local - In
build.zig, thecodegen_pathoption should bebuild/debug-local/codegen(instead ofbuild/debug/codegen) - In
.vscode/launch.json, many configurations use./build/debug/, change them as you see fit
Note that the WebKit folder, including build artifacts, is 8GB+ in size.
If you are using a JSC debug build and using VScode, make sure to run the C/C++: Select a Configuration command to configure intellisense to find the debug headers.
Note that if you change make changes to our WebKit fork, you will also have to change SetupWebKit.cmake to point to the commit hash.
Troubleshooting
'span' file not found on Ubuntu
The Clang compiler typically uses the libstdc++ C++ standard library by default. libstdc++ is the default C++ Standard Library implementation provided by the GNU Compiler Collection (GCC). While Clang may link against the libc++ library, this requires explicitly providing the -stdlib flag when running Clang.
Bun relies on C++20 features like std::span, which are not available in GCC versions lower than 11. GCC 10 doesn't have all of the C++20 features implemented. As a result, running make setup may fail with the following error:
fatal error: 'span' file not found
#include <span>
^~~~~~The issue may manifest when initially running bun setup as Clang being unable to compile a simple program:
The C++ compiler
"/usr/bin/clang++-19"
is not able to compile a simple test program.To fix the error, we need to update the GCC version to 11. To do this, we'll need to check if the latest version is available in the distribution's official repositories or use a third-party repository that provides GCC 11 packages. Here are general steps:
$ sudo apt update
$ sudo apt install gcc-11 g++-11
# If the above command fails with `Unable to locate package gcc-11` we need
# to add the APT repository
$ sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
# Now run `apt install` again
$ sudo apt install gcc-11 g++-11Now, we need to set GCC 11 as the default compiler:
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 100
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 100libarchive
If you see an error on macOS when compiling libarchive, run:
$ brew install pkg-configmacOS library not found for -lSystem
If you see this error when compiling, run:
$ xcode-select --installCannot find libatomic.a
Bun defaults to linking libatomic statically, as not all systems have it. If you are building on a distro that does not have a static libatomic available, you can run the following command to enable dynamic linking:
bun run build -DUSE_STATIC_LIBATOMIC=OFFThe built version of Bun may not work on other systems if compiled this way.
Using bun-debug
- Disable logging:
BUN_DEBUG_QUIET_LOGS=1 bun-debug ...(to disable all debug logging) - Enable logging for a specific zig scope:
BUN_DEBUG_EventLoop=1 bun-debug ...(to allowstd.log.scoped(.EventLoop)) - Bun transpiles every file it runs, to see the actual executed source in a debug build find it in
/tmp/bun-debug-src/...path/to/file, for example the transpiled version of/home/bun/index.tswould be in/tmp/bun-debug-src/home/bun/index.ts