--- title: Building Windows description: Building Bun on Windows --- Use [PowerShell 7 (`pwsh.exe`)](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.4) instead of the default `powershell.exe`. If you run into problems, ask in the [#contributing channel on our Discord](http://bun.com/discord). ## Prerequisites ### Enable Scripts By default, running unverified scripts is blocked. ```ps1 Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted ``` ### System Dependencies Bun v1.1 or later. The build uses Bun to run its own code generators. ```ps1 irm bun.sh/install.ps1 | iex ``` [Visual Studio](https://visualstudio.microsoft.com) with the "Desktop Development with C++" workload. While installing, also install Git if Git for Windows is not already installed. Install Visual Studio with the graphical wizard or through WinGet: ```ps1 winget install "Visual Studio Community 2022" --override "--add Microsoft.VisualStudio.Workload.NativeDesktop Microsoft.VisualStudio.Component.Git " -s msstore ``` After Visual Studio, you need the following: - LLVM 21.1.8 - Go - Rust (via rustup) - NASM - Perl - Ruby - Node.js rustup installs the Rust nightly toolchain pinned in `rust-toolchain.toml` on the first build. Use [Scoop](https://scoop.sh) to install these remaining tools. ```ps1 Scoop (x64) irm https://get.scoop.sh | iex scoop install nodejs-lts go rustup nasm ruby perl ccache # scoop seems to be buggy if you install llvm and the rest at the same time scoop install llvm@21.1.8 ``` For Windows ARM64, download LLVM 21.1.8 directly from GitHub releases (first version with ARM64 Windows builds): ```ps1 ARM64 # Download and install LLVM for ARM64 Invoke-WebRequest -Uri "https://github.com/llvm/llvm-project/releases/download/llvmorg-21.1.8/LLVM-21.1.8-woa64.exe" -OutFile "$env:TEMP\LLVM-21.1.8-woa64.exe" Start-Process -FilePath "$env:TEMP\LLVM-21.1.8-woa64.exe" -ArgumentList "/S" -Wait ``` Do not install these with WinGet or another package manager: you will likely get Strawberry Perl instead of a more minimal installation of Perl. Strawberry Perl adds many other utilities to `$Env:PATH` that conflict with MSVC and break the build. To build WebKit locally (optional, x64 only), install these packages: ```ps1 Scoop scoop install make cygwin python ``` ARM64 builds do not need Cygwin because WebKit is provided as a pre-built binary. From here on out, **use a PowerShell terminal with `.\scripts\vs-shell.ps1` sourced**. Load the script by running it: ```ps1 .\scripts\vs-shell.ps1 ``` To verify, check for an MSVC-only command such as `mt.exe`: ```ps1 Get-Command mt ``` Avoid installing `ninja` / `cmake` into your global path: you may end up building Bun without `.\scripts\vs-shell.ps1` sourced. ## Building ```ps1 bun run build # after the initial `bun run build` you can use the following to build ninja -Cbuild/debug ``` A successful build writes `bun-debug.exe` to the `build/debug` folder. ```ps1 .\build\debug\bun-debug.exe --revision ``` Add this folder to `$Env:PATH`: open the Start menu, type "Path", and use the environment variables menu to add `C:\.....\bun\build\debug` to the user environment variable `PATH`. Then restart your editor (if it still does not pick up the change, log out and log back in). ## Extra paths - The build extracts WebKit to `$Env:BUN_INSTALL\build-cache\webkit--debug` (`webkit--arm64-debug` on ARM64); `BUN_INSTALL` defaults to `~\.bun` ## Tests Run the test suite with `bun-debug test ` or with the wrapper script `bun run test `. The `bun run test` command runs every test file in a separate instance of `bun-debug.exe`, so a crash in the test runner does not stop the entire suite. ```ps1 # Run the entire test suite with reporter # the package.json script "test" uses "build/debug/bun-debug.exe" by default bun run test # Run an individual test file: bun-debug test node\fs bun-debug test "C:\bun\test\js\bun\resolve\import-meta.test.js" ``` ## Troubleshooting ### .rc file fails to build `llvm-rc.exe` is odd; don't use it. Use `rc.exe` instead: make sure you are in a Visual Studio dev terminal, and check `rc /?` to confirm it is `Microsoft Resource Compiler`. ### failed to write output 'bun-debug.exe': permission denied You cannot overwrite `bun-debug.exe` while it is open. You likely have a running instance, maybe in the VS Code debugger. ## Cross-compiling from Linux You can also build Windows binaries (both x64 and arm64) on a Linux host. The build uses the host LLVM's `clang-cl`, `lld-link`, `llvm-lib` and `llvm-rc` (part of every LLVM distribution). For headers and import libraries, the build also uses an "xwin splat" of the MSVC CRT/STL and Windows SDK. ### Prerequisites 1. The same LLVM version a native build uses (see `scripts/bootstrap.sh` `llvm_version_exact`), installed so that `clang-cl`, `lld-link`, `llvm-lib` and `llvm-rc` are available. On Debian/Ubuntu, `apt.llvm.org` packages provide all of them. 2. `nasm` (only needed for Windows x64; BoringSSL's x64 assembly is NASM syntax). 3. Rust std for the Windows targets (`rust-toolchain.toml` lists them; `rustup target add x86_64-pc-windows-msvc aarch64-pc-windows-msvc` if missing). 4. A Windows sysroot: an [xwin](https://github.com/Jake-Shadle/xwin) splat of the MSVC CRT, Windows SDK, and ATL laid out like a Visual Studio install. Downloading these components means accepting Microsoft's license terms for them. ```bash cargo install xwin # or download a release binary xwin --accept-license --arch x86_64,aarch64 --sdk-version 10.0.26100 --crt-version 14.44.17.14 --include-atl splat \ --use-winsysroot-style --preserve-ms-arch-notation --include-debug-libs \ --output /opt/winsysroot # clang-cl/lld-link look up SDK paths as "Include"/"Lib"; the splat writes # them lowercase, so alias both spellings (needs the same privileges as the # splat — configure creates these itself when the directory is writable). ln -s include "/opt/winsysroot/Windows Kits/10/Include" ln -s lib "/opt/winsysroot/Windows Kits/10/Lib" ``` The build looks for the sysroot at `/opt/winsysroot` (or `/opt/xwin`) automatically. If the sysroot is elsewhere, set `WINDOWS_SYSROOT=` or pass `--winsysroot=`. A user-writable path also lets configure manage the aliases for you. Configure validates the splat at the start of every cross build. CI agents bake the same splat into their images (`.buildkite/Dockerfile`, `scripts/bootstrap.sh`); when an agent doesn't have one, the build fetches it into its cache dir at configure time. ### Building ```bash # Debug builds bun run build --profile=windows-x64 bun run build --profile=windows-arm64 # Release builds bun run build --profile=windows-x64-release bun run build --profile=windows-arm64-release ``` Output lands in `build/debug-windows-x64/bun-debug.exe`, `build/release-windows-aarch64/bun-profile.exe` + `bun.exe`, and so on. Equivalent raw flags: `bun run build --os=windows --arch=aarch64`. The build does not run cross-compiled executables on the host (it skips the `--revision` smoke test), so test them on a Windows machine or under Wine. ### LTO x64 release cross builds support ThinLTO with cross-language (Rust↔C++) LTO. It's opt-in: ```bash bun run build --profile=windows-x64-release --lto=on ``` `--lto=on` does the following: - compiles Bun's C/C++ with `-flto=thin` - makes rustc emit LLVM bitcode (`-Clinker-plugin-lto`) - pulls the `bun-webkit-windows-amd64-lto` ThinLTO prebuilt - links everything with rustc's bundled `lld-link` (its LLVM is new enough to read both compilers' bitcode) There is no LTO for arm64, because there is no `-lto` WebKit prebuilt: LLVM's CodeView emitter can't handle ARM64 NEON tuple registers during LTO codegen. There is also no LTO for `--baseline`.