The --compile flag bundles your code and embeds the Bun runtime into a single executable binary. The resulting file runs without requiring Node.js, Bun, or any npm packages to be installed.
bun build ./index.ts --compile --outfile myapp
await Bun.build({
entrypoints: ["./index.ts"],
compile: {
outfile: "./myapp",
},
});
Run the output binary directly:
All imported files and npm packages are bundled into the executable, along with a copy of the Bun runtime. All built-in Bun and Node.js APIs are available.
Cross-compilation
Use --target to compile for a different OS or architecture than your current machine.
Linux
# Standard x64 (glibc)
bun build --compile --target=bun-linux-x64 ./index.ts --outfile myapp
# Older CPUs (pre-2013, nehalem)
bun build --compile --target=bun-linux-x64-baseline ./index.ts --outfile myapp
# Modern CPUs only (2013+, haswell — faster)
bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myapp
# ARM64 (Graviton, Raspberry Pi)
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myapp
# musl (Alpine Linux)
bun build --compile --target=bun-linux-x64-musl ./index.ts --outfile myapp
await Bun.build({
entrypoints: ["./index.ts"],
compile: {
target: "bun-linux-x64",
outfile: "./myapp",
},
});
Windows
bun build --compile --target=bun-windows-x64 ./index.ts --outfile myapp
# .exe is added automatically if not provided
await Bun.build({
entrypoints: ["./index.ts"],
compile: {
target: "bun-windows-x64",
outfile: "./myapp", // becomes myapp.exe
},
});
macOS
# Apple Silicon
bun build --compile --target=bun-darwin-arm64 ./index.ts --outfile myapp
# Intel
bun build --compile --target=bun-darwin-x64 ./index.ts --outfile myapp
await Bun.build({
entrypoints: ["./index.ts"],
compile: {
target: "bun-darwin-arm64",
outfile: "./myapp",
},
});
Supported targets
| Target | OS | Arch | Modern | Baseline | Libc |
|---|
bun-linux-x64 | Linux | x64 | ✅ | ✅ | glibc |
bun-linux-arm64 | Linux | arm64 | ✅ | N/A | glibc |
bun-linux-x64-musl | Linux | x64 | ✅ | ✅ | musl |
bun-linux-arm64-musl | Linux | arm64 | ✅ | N/A | musl |
bun-windows-x64 | Windows | x64 | ✅ | ✅ | - |
bun-windows-arm64 | Windows | arm64 | ✅ | N/A | - |
bun-darwin-x64 | macOS | x64 | ✅ | ✅ | - |
bun-darwin-arm64 | macOS | arm64 | ✅ | N/A | - |
On x64 platforms, the modern build requires CPUs that support AVX2 instructions (Intel Haswell / 2013+). Use the -baseline target for older hardware. If you see "Illegal instruction" errors, switch to -baseline.
Production deployment
For production binaries, combine minification, sourcemaps, and bytecode:
bun build --compile --minify --sourcemap --bytecode ./index.ts --outfile myapp
await Bun.build({
entrypoints: ["./index.ts"],
compile: { outfile: "./myapp" },
minify: true,
sourcemap: "linked",
bytecode: true,
});
--minify reduces the size of bundled code
--sourcemap embeds a sourcemap (compressed with zstd) so stack traces point to original source
--bytecode pre-compiles JavaScript to bytecode, reducing startup time by 2x for large apps
Full-stack executables
When your server code imports an HTML file, Bun bundles both the server and all frontend assets into a single binary:
import { serve } from "bun";
import index from "./index.html";
serve({
routes: {
"/": index,
"/api/hello": {
GET: () => Response.json({ message: "Hello from API" }),
},
},
});
bun build --compile ./server.ts --outfile myapp
./myapp
The resulting binary contains your server code, the Bun runtime, all frontend assets (HTML, CSS, JS), and every npm dependency. Deploy it anywhere — no installation needed.
Embedding assets
Use the with { type: "file" } import attribute to embed files into the executable:
import icon from "./icon.png" with { type: "file" };
import config from "./default-config.json" with { type: "file" };
import { file } from "bun";
// Read embedded file
const bytes = await file(icon).arrayBuffer();
// Serve it in an HTTP response
export default {
fetch(req: Request) {
return new Response(file(icon), {
headers: { "Content-Type": "image/png" },
});
},
};
At runtime, the import returns an internal path (prefixed $bunfs/) that Bun.file() and Node.js fs APIs can read.
Serving static assets
import favicon from "./favicon.ico" with { type: "file" };
import styles from "./styles.css" with { type: "file" };
import { file, serve } from "bun";
serve({
static: {
"/favicon.ico": file(favicon),
"/styles.css": file(styles),
},
fetch(req) {
return new Response("Not found", { status: 404 });
},
});
Embedding a SQLite database
import db from "./seed.db" with { type: "sqlite", embed: "true" };
console.log(db.query("SELECT * FROM users LIMIT 1").get());
The database is embedded read-write but changes are lost when the process exits.
Listing embedded files
import "./icon.png" with { type: "file" };
import "./data.json" with { type: "file" };
import { embeddedFiles } from "bun";
for (const blob of embeddedFiles) {
console.log(`${blob.name} — ${blob.size} bytes`);
}
Embed directories
bun build --compile ./index.ts ./public/**/*.png --outfile myapp
import { Glob } from "bun";
const pngFiles = Array.from(new Glob("./public/**/*.png").scanSync("."));
await Bun.build({
entrypoints: ["./index.ts", ...pngFiles],
compile: { outfile: "./myapp" },
});
Build-time constants
Use --define to inject values at compile time:
bun build --compile --define BUILD_VERSION='"1.2.3"' ./index.ts --outfile myapp
await Bun.build({
entrypoints: ["./index.ts"],
compile: { outfile: "./myapp" },
define: {
BUILD_VERSION: JSON.stringify("1.2.3"),
BUILD_TIME: JSON.stringify(new Date().toISOString()),
},
});
Workers
To use Worker in a standalone executable, include the worker’s entrypoint in the build:
bun build --compile ./index.ts ./worker.ts --outfile myapp
await Bun.build({
entrypoints: ["./index.ts", "./worker.ts"],
compile: { outfile: "./myapp" },
});
new Worker(new URL("./worker.ts", import.meta.url));
Windows-specific options
bun build --compile --windows-icon=./icon.ico ./app.ts --outfile myapp
bun build --compile --windows-hide-console ./app.ts --outfile myapp
await Bun.build({
entrypoints: ["./app.ts"],
compile: {
outfile: "./myapp",
windows: {
icon: "./path/to/icon.ico",
hideConsole: true,
title: "My Application",
publisher: "My Company",
version: "1.0.0",
description: "A standalone app",
copyright: "Copyright 2025",
},
},
});
Windows-specific flags cannot be used when cross-compiling from a non-Windows machine.
macOS code signing
Fix Gatekeeper warnings by codesigning your binary:
codesign --deep --force -vvvv --sign "XXXXXXXXXX" \
--entitlements entitlements.plist ./myapp
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
Runtime flags via BUN_OPTIONS
Pass runtime flags to a compiled executable without recompiling:
BUN_OPTIONS="--smol" ./myapp
BUN_OPTIONS="--cpu-prof-md" ./myapp
compile API reference
interface CompileBuildOptions {
target?: BunBuildTarget; // Cross-compilation target
outfile?: string; // Output binary path
execArgv?: string[]; // Embedded process.execArgv
autoloadTsconfig?: boolean; // Load tsconfig.json at runtime (default: false)
autoloadPackageJson?: boolean; // Load package.json at runtime (default: false)
autoloadDotenv?: boolean; // Load .env files (default: true)
autoloadBunfig?: boolean; // Load bunfig.toml (default: true)
windows?: {
icon?: string;
hideConsole?: boolean;
title?: string;
publisher?: string;
version?: string;
description?: string;
copyright?: string;
};
}
Usage forms:
// Boolean — compile for current platform
compile: true
// Target string — cross-compile
compile: "bun-linux-x64"
// Full options
compile: {
target: "bun-linux-x64",
outfile: "./dist/myapp",
}
Limitations
The --compile flag does not support:
--outdir (use outfile instead, except when combined with --splitting)
--public-path
--target=node
--no-bundle