How to Build Single-File Executables with Bun for Distribution

Bun’s --compile flag bundles your JavaScript or TypeScript application and embeds the Bun runtime into a single native binary that runs on any matching OS/architecture without requiring a separate Bun installation.

The oven-sh/bun repository provides a sophisticated compilation pipeline that transforms your projects into standalone distributables. When you build single-file executables with Bun, the resulting binary contains your bundled code, the JavaScriptCore engine, and optional configuration files, creating a closed-world deployment artifact.

How Bun Compiles Single-File Executables

Bun’s compilation process follows a three-stage pipeline defined primarily in src/cli/build_command.zig (lines 103-167):

  1. Bundling – The entry point and all dependencies are resolved and bundled. The resolver at src/resolver/resolver.zig (line 766) skips external module lookups to ensure a self-contained bundle.
  2. Runtime Embedding – The bundled output is linked against the Bun runtime binary, creating a native executable (ELF for Linux, PE for Windows, or Mach-O for macOS).
  3. Asset Injection – Optional files like .env, bunfig.toml, or source maps are embedded into the final binary.

The feature is exposed through the --compile flag defined in src/cli/Arguments.zig (lines 160-210), which implies --production and validates that you do not use incompatible flags like --no-bundle or --outdir.

Creating Your First Standalone Executable

To compile a basic TypeScript or JavaScript file into a distributable binary, use the --compile flag with an entry point:

bun build src/index.ts --compile --outfile my-app

This command produces ./my-app (or ./my-app.exe on Windows), a native executable that includes:

  • Your minified application code
  • The Bun JavaScript runtime (JavaScriptCore)
  • Default autoload configurations

The src/compile_target.zig module manages the platform-specific compilation targets, ensuring the output matches your host architecture unless overridden.

Essential Compilation Flags

Output Configuration

Control the destination and behavior of your compiled binary using these flags validated in src/cli/build_command.zig:

  • --outfile <PATH> – Specifies the output filename. Cannot be named bun.
  • --compile-exec-argv <STR> – Prepends default arguments to process.argv when the binary runs.
bun build src/cli.ts --compile --compile-exec-argv "--mode=production" --outfile my-cli

Runtime Autoloading

By default, Bun automatically embeds certain configuration files. These options are defined in src/cli/Arguments.zig:

  • --compile-autoload-dotenv (default: enabled) – Embeds a .env file loaded at runtime.
  • --compile-autoload-bunfig (default: enabled) – Embeds bunfig.toml.
  • --compile-autoload-tsconfig (default: disabled) – Embeds tsconfig.json.
  • --compile-autoload-package-json (default: disabled) – Embeds package.json.

Disable any autoload feature with the --no- prefix:

bun build src/index.ts --compile --no-compile-autoload-dotenv --outfile my-app

Cross-Compilation and Custom Runtimes

Target different operating systems using the --target flag or provide a pre-downloaded runtime binary:


# Cross-compile for Windows from macOS/Linux

bun build src/index.ts --compile --target=win --outfile my-app.exe

# Use a custom runtime binary for offline builds

bun build src/index.ts --compile \
  --compile-executable-path /path/to/bun-windows-x64 \
  --outfile my-app.exe

Windows Metadata

When targeting Windows (--target=win), you can embed PE metadata:

  • --windows-icon <PATH> – Sets the application icon (.ico file).
  • --windows-title <STR>
  • --windows-version <STR>
  • --windows-product-name <STR>

Embedding Source Maps for Debugging

For production debugging, include source maps that get embedded by src/sourcemap/Mapping.zig (line 228):

bun build src/index.ts \
  --compile \
  --minify \
  --sourcemap=external \
  --outfile my-app

This bundles the source map data directly into the executable, enabling accurate stack traces without external files.

Complete Distribution Examples

Basic Web Server Executable

bun build src/server.ts --compile --minify --outfile my-server
./my-server  # Starts the server immediately

CLI Tool with Default Arguments

bun build src/tool.ts \
  --compile \
  --compile-exec-argv "--help" \
  --compile-autoload-dotenv \
  --outfile my-tool

Windows Application with Branding

bun build src/app.ts \
  --compile \
  --target=win \
  --windows-icon=assets/app.ico \
  --windows-title="My Application" \
  --windows-product-name="MyProduct" \
  --outfile dist/my-app.exe

Summary

  • Use bun build --compile to create native executables that embed the Bun runtime along with your JavaScript/TypeScript code.
  • Implementation resides in src/cli/build_command.zig (core logic), src/cli/Arguments.zig (flag definitions), and src/compile_target.zig (target handling).
  • Autoload flags (--compile-autoload-*) control whether .env, bunfig.toml, and other config files are embedded in the binary.
  • Cross-compilation is supported via --target and --compile-executable-path for building Windows binaries on Unix systems.
  • Source maps can be embedded using --sourcemap with compile, handled by src/sourcemap/Mapping.zig.

Frequently Asked Questions

What is the difference between bun build and bun build --compile?

Regular bun build produces bundled JavaScript files that still require the Bun runtime to execute, while bun build --compile generates a native executable (ELF, PE, or Mach-O) with the runtime fully embedded. According to the source in src/cli/build_command.zig, the --compile flag implies --production and produces a closed-world binary that runs independently of any installed JavaScript runtime.

Can I cross-compile Bun executables for different operating systems?

Yes, use the --target flag (e.g., --target=win, --target=linux, or --target=darwin) to specify the destination platform. Bun automatically downloads the appropriate runtime binary for the target, or you can provide a custom path via --compile-executable-path for offline cross-compilation scenarios.

How do I include environment variables in a compiled Bun executable?

Use the --compile-autoload-dotenv flag (enabled by default as defined in src/cli/Arguments.zig) to embed a .env file into the binary. When the executable runs, it automatically loads these variables. Alternatively, disable this with --no-compile-autoload-dotenv if you prefer the binary to read from an external .env file at runtime.

Do Bun single-file executables require Node.js or Bun on the target machine?

No. The resulting binary is completely self-contained, including the JavaScriptCore engine and all necessary runtime components. The target machine only needs to match the compiled architecture and operating system; no separate Bun installation, Node.js, or npm dependencies are required to run the executable.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →