400 lines
16 KiB
Plaintext
400 lines
16 KiB
Plaintext
---
|
|||
|
|
title: Contributing
|
||
|
|
description: Contributing to Bun
|
||
|
|
---
|
||
|
|
|
||
|
|
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, see [Building Windows](/project/building-windows).
|
||
|
|
|
||
|
|
## Using Nix (Alternative)
|
||
|
|
|
||
|
|
The repository includes a Nix flake as an alternative to installing dependencies manually:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
nix develop
|
||
|
|
bun bd
|
||
|
|
```
|
||
|
|
|
||
|
|
`nix develop` provides all dependencies in an isolated, reproducible environment without requiring sudo.
|
||
|
|
|
||
|
|
## Install Dependencies (Manual)
|
||
|
|
|
||
|
|
Using your system's package manager, install Bun's dependencies:
|
||
|
|
|
||
|
|
<CodeGroup>
|
||
|
|
|
||
|
|
```bash macOS (Homebrew)
|
||
|
|
brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rustup-init ruby
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash Ubuntu/Debian
|
||
|
|
sudo apt install curl wget lsb-release software-properties-common cmake git golang libtool ninja-build pkg-config ruby-full xz-utils
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash Arch
|
||
|
|
sudo pacman -S base-devel cmake git go libiconv libtool make ninja pkg-config python rustup sed unzip ruby
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash Fedora
|
||
|
|
sudo dnf install clang21 llvm21 lld21 cmake git golang libtool ninja-build pkg-config ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash openSUSE Tumbleweed
|
||
|
|
sudo zypper install go cmake ninja automake git icu rustup
|
||
|
|
```
|
||
|
|
|
||
|
|
</CodeGroup>
|
||
|
|
|
||
|
|
Bun is written in Rust and requires a specific nightly toolchain (pinned in `rust-toolchain.toml`). Install Rust with [rustup](https://rustup.rs) rather than your distro's `rust`/`cargo` packages — the build scripts use rustup to automatically install and update the pinned nightly:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||
|
|
```
|
||
|
|
|
||
|
|
Before starting, install a release build of Bun: the build uses Bun's bundler to transpile and minify code, and to run the code generation scripts.
|
||
|
|
|
||
|
|
<CodeGroup>
|
||
|
|
|
||
|
|
```bash Native
|
||
|
|
curl -fsSL https://bun.com/install | bash
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash npm
|
||
|
|
npm install -g bun
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash Homebrew
|
||
|
|
brew tap oven-sh/bun
|
||
|
|
brew install bun
|
||
|
|
```
|
||
|
|
|
||
|
|
</CodeGroup>
|
||
|
|
|
||
|
|
### Optional: Install `ccache`
|
||
|
|
|
||
|
|
`ccache` caches compilation artifacts, which speeds up rebuilds:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# For macOS
|
||
|
|
brew install ccache
|
||
|
|
|
||
|
|
# For Ubuntu/Debian
|
||
|
|
sudo apt install ccache
|
||
|
|
|
||
|
|
# For Arch
|
||
|
|
sudo pacman -S ccache
|
||
|
|
|
||
|
|
# For Fedora
|
||
|
|
sudo dnf install ccache
|
||
|
|
|
||
|
|
# For openSUSE
|
||
|
|
sudo zypper install ccache
|
||
|
|
```
|
||
|
|
|
||
|
|
The build scripts detect and use `ccache` automatically if it's available. Check cache statistics with `ccache --show-stats`.
|
||
|
|
|
||
|
|
## Install LLVM
|
||
|
|
|
||
|
|
Bun requires LLVM 21.1.8 (`clang` is part of LLVM). The build system enforces this version: a mismatched version causes memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
|
||
|
|
|
||
|
|
<CodeGroup>
|
||
|
|
|
||
|
|
```bash macOS (Homebrew)
|
||
|
|
brew install llvm@21
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash Ubuntu/Debian
|
||
|
|
# 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 -- 21 all
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash Arch
|
||
|
|
sudo pacman -S llvm clang lld
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash Fedora
|
||
|
|
sudo dnf install llvm clang lld-devel
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash openSUSE Tumbleweed
|
||
|
|
sudo zypper install clang21 lld21 llvm21
|
||
|
|
```
|
||
|
|
|
||
|
|
</CodeGroup>
|
||
|
|
|
||
|
|
If none of these work, install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-21.1.8).
|
||
|
|
|
||
|
|
Make sure Clang/LLVM 21 is in your path:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
which clang-21
|
||
|
|
```
|
||
|
|
|
||
|
|
If not, add it manually:
|
||
|
|
|
||
|
|
<CodeGroup>
|
||
|
|
|
||
|
|
```bash macOS (Homebrew)
|
||
|
|
# use fish_add_path if you're using fish
|
||
|
|
# use path+="$(brew --prefix llvm@21)/bin" if you are using zsh
|
||
|
|
export PATH="$(brew --prefix llvm@21)/bin:$PATH"
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash Arch
|
||
|
|
# use fish_add_path if you're using fish
|
||
|
|
export PATH="$PATH:/usr/lib/llvm21/bin"
|
||
|
|
```
|
||
|
|
|
||
|
|
</CodeGroup>
|
||
|
|
|
||
|
|
<Warning>
|
||
|
|
⚠️ On Ubuntu \<= 20.04, you may need to install the C++ standard library separately. See the [troubleshooting section](#span-file-not-found-on-ubuntu).
|
||
|
|
</Warning>
|
||
|
|
|
||
|
|
## Building Bun
|
||
|
|
|
||
|
|
After cloning the repository, run the following command to build. This can take a while: it downloads and builds dependencies.
|
||
|
|
|
||
|
|
```bash
|
||
|
|
bun run build
|
||
|
|
```
|
||
|
|
|
||
|
|
The binary is at `./build/debug/bun-debug`. It is recommended to add this to your `$PATH`. To verify the build worked, print its version:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
build/debug/bun-debug --version
|
||
|
|
x.y.z_debug
|
||
|
|
```
|
||
|
|
|
||
|
|
## VSCode
|
||
|
|
|
||
|
|
VSCode is the recommended IDE for working on Bun; the repository includes configuration for it. After opening the repository, run `Extensions: Show Recommended Extensions` to install the recommended extensions for Rust and C++. rust-analyzer picks up the workspace `Cargo.toml` automatically and uses the pinned toolchain in `rust-toolchain.toml` for analysis, so diagnostics match the build.
|
||
|
|
|
||
|
|
If you use a different editor, point rust-analyzer (or your editor's Rust plugin) at the repo root — the Cargo workspace and `rust-toolchain.toml` are discovered automatically.
|
||
|
|
|
||
|
|
We recommend adding `./build/debug` to your `$PATH` so that you can run `bun-debug` in your terminal:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
bun-debug
|
||
|
|
```
|
||
|
|
|
||
|
|
## Running 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.
|
||
|
|
|
||
|
|
```sh
|
||
|
|
bun bd <args>
|
||
|
|
bun bd test foo.test.ts
|
||
|
|
bun bd ./foo.ts
|
||
|
|
```
|
||
|
|
|
||
|
|
A full debug build can take a few minutes when Rust or C++ has changed; cargo's incremental compilation makes subsequent Rust-only rebuilds much faster. If your development workflow is "change one line, save, rebuild", you will still spend too much time waiting for the link step. Instead:
|
||
|
|
|
||
|
|
- Batch up your changes
|
||
|
|
- Use `cargo check -p <crate>` (or `bun run rust:check` for the whole workspace) to type-check Rust changes without linking. `bun run watch` runs `cargo check` on every save.
|
||
|
|
- Ensure rust-analyzer is running for inline diagnostics (the recommended VSCode extensions set this up)
|
||
|
|
- Prefer using the debugger ("CodeLLDB" in VSCode) to step through the code.
|
||
|
|
- Use debug logs. `BUN_DEBUG_<scope>=1` enables debug logging for the corresponding `declare_scope!(<scope>, ...)` / `scoped_log!(<scope>, ...)` logs. Set `BUN_DEBUG_QUIET_LOGS=1` to disable all debug logging that isn't explicitly enabled. To dump debug logs into a file, set `BUN_DEBUG=<path-to-file>.log`. Debug logs are removed in release builds.
|
||
|
|
- src/js/\*\*.ts changes rebuild almost instantly. Single-crate Rust changes and C++ changes are incremental; only the final link is unavoidable.
|
||
|
|
|
||
|
|
## Code generation scripts
|
||
|
|
|
||
|
|
Bun's build process runs several code generation scripts automatically when certain files change:
|
||
|
|
|
||
|
|
- `./src/codegen/generate-jssink.ts` -- Generates `build/debug/codegen/JSSink.cpp`, `build/debug/codegen/JSSink.h` which implement various classes for interfacing with `ReadableStream`. This is internally how `FileSink`, `ArrayBufferSink`, `"type": "direct"` streams and other code related to streams work.
|
||
|
|
- `./src/codegen/generate-classes.ts` -- Generates Rust & C++ bindings for JavaScriptCore classes implemented in Rust. `**/*.classes.ts` files define the interfaces for classes, methods, prototypes, and getters/setters; the code generator reads them to generate the boilerplate that implements the JavaScript objects in C++ and wires them up to Rust.
|
||
|
|
- `./src/codegen/cppbind.ts` -- Scans the C++ bindings for functions marked with an export attribute and generates automatic Rust FFI wrappers (`cpp.rs`) for them.
|
||
|
|
- `./src/codegen/bundle-modules.ts` -- Bundles built-in modules like `node:fs`, `bun:ffi` into files included in the final binary. In development, these can be reloaded without rebuilding native code (you still need to run `bun 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 like `ReadableStream` and `WritableStream`. 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 implementations can be copy-pasted 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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
bun run build:release
|
||
|
|
```
|
||
|
|
|
||
|
|
The binaries are at `./build/release/bun` and `./build/release/bun-profile`.
|
||
|
|
|
||
|
|
### Download release build from pull requests
|
||
|
|
|
||
|
|
You can run the release build from a pull request without building it locally, which is useful for manually testing changes before they are merged.
|
||
|
|
|
||
|
|
Use the `bun-pr` npm package:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
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 only
|
||
|
|
```
|
||
|
|
|
||
|
|
`bun-pr` downloads the release build from the pull request's GitHub Actions artifacts and adds it to `$PATH` as `bun-${pr-number}`, so you can run it directly:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
bun-1234566 --version
|
||
|
|
```
|
||
|
|
|
||
|
|
You may need the `gh` CLI installed to authenticate with GitHub.
|
||
|
|
|
||
|
|
### Viewing CI failures from the terminal
|
||
|
|
|
||
|
|
Bun's CI runs on BuildKite. Install the [BuildKite CLI](https://github.com/buildkite/cli) (`brew install buildkite/buildkite/bk`) and set `BUILDKITE_API_TOKEN` to a read-scoped [API token](https://buildkite.com/user/api-access-tokens). The repo includes a `.bk.yaml` so `bk` commands default to the `bun` pipeline.
|
||
|
|
|
||
|
|
```sh
|
||
|
|
bun run ci:status # progress summary for the current branch's latest build
|
||
|
|
bun run ci:errors # rendered test-failure output, tagged [new] vs [also on main]
|
||
|
|
bun run ci:logs # save full logs for each failed job to ./tmp/ci-<build>/
|
||
|
|
bun run ci:watch # watch until the build finishes
|
||
|
|
bun run ci:find # print the build number (compose with raw `bk`)
|
||
|
|
```
|
||
|
|
|
||
|
|
All of these accept a target: `#1234` (PR number), a PR URL, a branch name, or a build number. Without one they use the current git branch.
|
||
|
|
|
||
|
|
## AddressSanitizer
|
||
|
|
|
||
|
|
[AddressSanitizer](https://en.wikipedia.org/wiki/AddressSanitizer) helps find memory issues, and is enabled by default in debug builds of Bun on Linux and macOS. This covers the Rust code, the C++ bindings, and all dependencies. It makes the build take about 2x longer; if that's stopping you from being productive you can disable it with `bun run build:debug:noasan` (or pass `--asan=off` to `scripts/build.ts`), but generally we recommend batching your changes up between builds.
|
||
|
|
|
||
|
|
To build a release build with AddressSanitizer, run:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
bun run build:asan
|
||
|
|
```
|
||
|
|
|
||
|
|
CI runs the test suite with at least one target built with AddressSanitizer.
|
||
|
|
|
||
|
|
## 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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Clone WebKit into ./vendor/WebKit
|
||
|
|
git clone https://github.com/oven-sh/WebKit vendor/WebKit
|
||
|
|
|
||
|
|
# Check out the version pinned in WEBKIT_VERSION in scripts/build/deps/webkit.ts
|
||
|
|
# (a commit sha or an autobuild-* release tag; this handles both)
|
||
|
|
bun sync-webkit-source
|
||
|
|
|
||
|
|
# Build bun with the local JSC build — this automatically configures and builds JSC
|
||
|
|
bun run build:local
|
||
|
|
```
|
||
|
|
|
||
|
|
`bun run build:local` handles everything: configuring JSC, building JSC, and building Bun. On subsequent runs, JSC rebuilds incrementally if any WebKit sources changed. `ninja -Cbuild/debug-local` also works after the first build, and builds both Bun and JSC.
|
||
|
|
|
||
|
|
The build output goes to `./build/debug-local` (instead of `./build/debug`), so you'll need to update a couple of places:
|
||
|
|
|
||
|
|
- The first line in `src/js/builtins.d.ts`
|
||
|
|
- The `CompilationDatabase` line in `.clangd` config should be `CompilationDatabase: build/debug-local`
|
||
|
|
- In `.vscode/launch.json`, many configurations use `./build/debug/`, change them as you see fit
|
||
|
|
|
||
|
|
The WebKit folder, including build artifacts, is 8GB+ in size.
|
||
|
|
|
||
|
|
If you are using a JSC debug build with VSCode, run the `C/C++: Select a Configuration` command so IntelliSense finds the debug headers.
|
||
|
|
|
||
|
|
If you make changes to Bun's [WebKit fork](https://github.com/oven-sh/WebKit), you also have to change `WEBKIT_VERSION` in `scripts/build/deps/webkit.ts` to point to your commit hash or release tag.
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### 'span' file not found on Ubuntu
|
||
|
|
|
||
|
|
<Warning>
|
||
|
|
⚠️ These instructions are specific to Ubuntu. The same issues are unlikely on other Linux distributions.
|
||
|
|
</Warning>
|
||
|
|
|
||
|
|
Clang uses `libstdc++`, the C++ standard library implementation provided by the GNU Compiler Collection (GCC), by default. Clang can link against `libc++` instead, but that requires explicitly passing the `-stdlib` flag.
|
||
|
|
|
||
|
|
Bun relies on C++20 features like `std::span`, which are not available in GCC versions lower than 11. As a result, running `bun run build` may fail with the following error:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
fatal error: 'span' file not found
|
||
|
|
#include <span>
|
||
|
|
^~~~~~
|
||
|
|
```
|
||
|
|
|
||
|
|
The issue may also surface when first running `bun run build`, with Clang unable to compile a simple program:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
The C++ compiler
|
||
|
|
|
||
|
|
"/usr/bin/clang++-21"
|
||
|
|
|
||
|
|
is not able to compile a simple test program.
|
||
|
|
```
|
||
|
|
|
||
|
|
To fix the error, update GCC to version 11. It may be available in your distribution's official repositories; otherwise, add a third-party repository that provides GCC 11 packages:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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++-11
|
||
|
|
```
|
||
|
|
|
||
|
|
Then set GCC 11 as the default compiler:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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 100
|
||
|
|
```
|
||
|
|
|
||
|
|
### libarchive
|
||
|
|
|
||
|
|
If you see an error on macOS when compiling `libarchive`, run:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
brew install pkg-config
|
||
|
|
```
|
||
|
|
|
||
|
|
### macOS `library not found for -lSystem`
|
||
|
|
|
||
|
|
If you see this error when compiling, run:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
xcode-select --install
|
||
|
|
```
|
||
|
|
|
||
|
|
### Cannot 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, enable dynamic linking with:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
bun run build --static-libatomic=off
|
||
|
|
```
|
||
|
|
|
||
|
|
The 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 scope: `BUN_DEBUG_EventLoop=1 bun-debug ...` (to enable `scoped_log!(EventLoop, ...)` output)
|
||
|
|
- 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.ts` is in `/tmp/bun-debug-src/home/bun/index.ts`
|
||
|
|
|
||
|
|
## Contributing to the docs
|
||
|
|
|
||
|
|
The docs are the MDX files in `docs/` in the Bun repository. [bun.com/docs](https://bun.com/docs) is built from them.
|
||
|
|
|
||
|
|
### Voice
|
||
|
|
|
||
|
|
A docs page describes what Bun does and what you can do with it. Write it so that a developer who is new to Bun can read the page once and act on it. These guidelines are adapted from the [Next.js docs contribution guide](https://nextjs.org/docs/community/contribution-guide#voice):
|
||
|
|
|
||
|
|
- Write short sentences that each make one point. If a sentence needs several commas or a parenthetical, split it up or turn it into a list.
|
||
|
|
- Use plain words: "use" rather than "utilize", "to" rather than "in order to". Cut filler such as "Note that" and "Please".
|
||
|
|
- Use the active voice and name the actor: "Bun reads `bunfig.toml`", rather than "`bunfig.toml` is read". A sentence built around "is" and "by" is usually passive.
|
||
|
|
- Describe current behavior in the present tense: "Bun installs the package", rather than "Bun will install the package".
|
||
|
|
- Name the subject when "this" or "it" could refer to more than one thing: "`--isolate` is how Jest behaves by default", rather than "This is how Jest behaves by default".
|
||
|
|
- Address the reader as "you", and make Bun (or the specific tool) the other actor: "Bun caches the tarball", rather than "we cache the tarball" or "let's cache the tarball".
|
||
|
|
- Leave out "easy", "simple", "just", and "quick". They add nothing when a task is easy and discourage readers when it is not. State the concrete property instead: "one command", "no configuration".
|
||
|
|
- Say what to do rather than what to avoid: "use `port: 0` so the operating system picks a free port", rather than "don't hardcode ports". State limitations plainly; a limitation is a fact, not a warning to the reader.
|
||
|
|
- Use gender-neutral language: "developers", "users", "they".
|
||
|
|
- Make link text name its destination: "see [`bun install`](/pm/cli/install)", rather than "see here".
|
||
|
|
- Run every code example before you publish it, and check option names and defaults against the implementation on `main`.
|