Introduction
Bun 1.1 marked a watershed moment for the alternative JavaScript runtime. With this release, Bun achieved native Windows support (no longer requiring WSL), dramatically improved Node.js API compatibility, and delivered measurable performance gains across package installation, HTTP serving, and file I/O. For teams evaluating Bun as a Node.js replacement, version 1.1 removed the most significant adoption blockers.
The JavaScript runtime landscape before Bun 1.1 was a two-horse race: Node.js for production stability and Deno for developer experience. Bun entered with raw speed but lacked the compatibility and platform support needed for broad adoption. Version 1.1 changed that calculus by supporting Windows natively, passing 90% of Node.js's test suite, and introducing features like bun patch for modifying dependencies and bun audit for security scanning. This guide explores what's new in Bun 1.1, how its internals achieve such dramatic performance improvements, and how to leverage its features in real-world projects.
Understanding Bun's Architecture
Before diving into the 1.1 changes, it's worth understanding why Bun is fast. Bun is built on three foundational technologies that set it apart from Node.js and Deno:
JavaScriptCore (JSC) Engine: Unlike Node.js (V8) and Deno (V8), Bun uses Apple's JavaScriptCore engine from WebKit. JSC was designed for Safari's strict performance requirements and features a four-tier compilation pipeline: interpreter → baseline JIT → optimizing JIT → DFG optimizing JIT. This multi-tier approach means JSC can start executing code quickly while progressively optimizing hot paths—a natural fit for server workloads where startup time matters as much as throughput.
Zig Programming Language: Bun's core is written in Zig, a systems programming language that gives direct control over memory allocation, SIMD instructions, and system calls. Where Node.js delegates to libuv for asynchronous I/O, Bun implements its own I/O layer using io_uring on Linux, kqueue on macOS, and IOCP on Windows. This eliminates the overhead of cross-platform abstraction layers and allows Bun to make zero-copy optimizations that would be impossible through libuv.
Native Bindings: Bun doesn't just reimplement Node.js APIs—it reimplements the underlying C libraries that Node.js wraps. For example, Bun's fetch() uses a custom HTTP parser written in Zig rather than wrapping llhttp. Its TLS implementation uses BoringSSL with Zig bindings rather than OpenSSL through Node.js's crypto module. These native bindings reduce the boundary-crossing overhead between JavaScript and native code.
What's New in Bun 1.1
Windows Native Support
Prior to 1.1, Bun on Windows required WSL (Windows Subsystem for Linux), which added friction and complexity. Bun 1.1 ships as a native Windows binary built with Zig's cross-compilation capabilities. The Windows build supports:
- Full filesystem operations with correct path handling (
\vs/) - Native Windows process spawning using
CreateProcess - PowerShell and CMD integration for
bun runscripts - Windows-specific optimizations for file I/O using IOCP (I/O Completion Ports)
- Automatic detection of
.exeextensions in script execution
The Windows build is not a port—it shares the same codebase as macOS and Linux, with platform-specific code paths for filesystem, networking, and process management. This means bug fixes and features land on all three platforms simultaneously. Bun's use of Zig makes this cross-platform story particularly clean: Zig's comptime feature and standard library abstractions allow platform-specific code to coexist without preprocessor macros or conditional compilation blocks.
Node.js Compatibility Improvements
Bun 1.1 passes approximately 90% of Node.js's test suite, up from ~70% in Bun 1.0. Key additions include:
node:vm: Thevmmodule now supportsvm.Script,vm.createContext, andvm.runInContext. This enables sandboxed code execution patterns used by testing frameworks and code playgrounds.node:async_hooks:AsyncLocalStorageworks correctly, enabling frameworks like Next.js and Express that depend on request context propagation through asynchronous call chains.node:worker_threads: Worker threads are supported with properSharedArrayBufferandMessageChannelsemantics. Bun implements workers using its own thread pool rather than libuv, which means worker communication has lower latency than Node.js for message-passing patterns.node:crypto: Additional algorithms including Ed25519, X25519, and HKDF. Bun uses BoringSSL (Google's fork of OpenSSL) which provides a more modern and audited cryptographic implementation.node:dns: The DNS resolver now supportsresolve4,resolve6, andresolveMxwith c-ares for non-blocking DNS resolution.node:net: TCP server and client implementations improved with better handling ofhalfOpenconnections and properallowHalfOpensemantics.node:tls: TLS 1.3 support is now complete, and SNI (Server Name Indication) callbacks work correctly for multi-domain HTTPS servers.
These improvements mean that most Node.js applications—including complex frameworks like Next.js, NestJS, and Fastify—run on Bun without modification.
Performance Improvements in Detail
Bun 1.1 introduces several performance optimizations that compound across the stack:
Package Installation: bun install is 2-5x faster than 1.0 for large dependency trees. The improvement comes from three changes: (1) improved parallelism in the resolution phase where Bun now resolves up to 128 dependencies concurrently, (2) a new caching layer that stores extracted tarballs in ~/.bun/install/cache with content-addressable storage, and (3) reduced memory allocation during lockfile generation by reusing buffer allocations across resolution steps.
HTTP Serving: Bun.serve() achieves 2.8x higher throughput than Node.js's built-in HTTP server. The advantage comes from Bun's custom HTTP parser (written in Zig) which processes HTTP/1.1 requests in a single pass without allocating intermediate objects. Node.js's http module, by contrast, creates IncomingMessage and ServerResponse objects for each request and delegates parsing to the llhttp C library through a N-API boundary.
File I/O: Bun.file() uses memory-mapped I/O on Windows, matching the performance characteristics of the macOS and Linux implementations. For large files, Bun uses mmap (or MapViewOfFile on Windows) to avoid copying data between kernel and user space. The Bun.write() function batches multiple writes into a single syscall using writev on Unix platforms.
Startup Time: Cold startup improved by ~15% through lazy initialization of built-in modules. Bun defers loading node:crypto, node:tls, and node:dns until first use, reducing the module graph that must be evaluated before the first line of user code runs.
Architecture and Design Patterns
The bun patch Command
One of Bun 1.1's most practical additions is bun patch, which lets you modify dependencies in node_modules and persist those changes across installs. This is similar to patch-package but built into the package manager:
# Generate a patch for a dependency
bun patch @some/package
# Edit the files in node_modules/@some/package
# ...
# Save the patch
bun patch --commit @some/packagePatches are stored in the patches/ directory and applied automatically on bun install. This eliminates the need for patch-package as a separate dependency and avoids the common pitfall of forgetting to run npx patch-package after install. Bun's implementation also handles patch conflicts more gracefully—if a patch fails to apply cleanly, bun install reports the specific hunks that failed rather than silently producing a broken installation.
The bun audit Command
Bun 1.1 introduces built-in security auditing:
# Check for known vulnerabilities
bun audit
# Output as JSON for CI integration
bun audit --json
# Audit with severity threshold
bun audit --level moderateThe audit command checks dependencies against the GitHub Advisory Database and reports vulnerabilities with severity levels, affected versions, and remediation guidance. Unlike npm audit, Bun's implementation queries the advisory database asynchronously and caches results for 24 hours, making repeated audits nearly instant.
Text Lockfile
Bun 1.1 introduces bun.lock as a human-readable text alternative to the binary bun.lockb. The text lockfile is easier to review in pull requests and merge conflicts:
# Generate a text lockfile
bun install --save-text-lockfileThe text lockfile contains the resolved versions, integrity hashes, and dependency graph in a structured format. This is particularly valuable for teams with strict code review processes where reviewers need to understand exactly what changed in dependency resolution.
Glob Pattern Support
Bun 1.1 adds native glob support in the Bun.Glob API, which is significantly faster than JavaScript-based glob libraries:
const glob = new Glob("**/*.ts");
// Scan a directory tree
for (const file of glob.scanSync("./src")) {
console.log(file);
}
// Use in imports
const files = Array.from(glob.scanSync("./src"));
console.log(`Found ${files.length} TypeScript files`);The glob implementation is written in Zig and uses SIMD instructions for pattern matching, making it 5-10x faster than popular JavaScript glob libraries like glob or fast-glob.
Step-by-Step Implementation
Migration from Node.js
# Install Bun
curl -fsSL https://bun.sh/install | bash
# In your existing Node.js project
bun install # Replace npm install
bun run dev # Replace npm run dev
bun test # Replace npm test (if using Jest-compatible tests)Configuring for Windows
// package.json
{
"scripts": {
"dev": "bun run --watch src/index.ts",
"build": "bun build src/index.ts --outdir dist --target node",
"start": "bun run dist/index.js",
"test": "bun test"
}
}Using the Built-in Bundler
// build.ts
const result = await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
target: "node",
format: "esm",
splitting: true,
minify: true,
sourcemap: "external",
});
if (!result.success) {
console.error("Build failed:");
for (const log of result.logs) {
console.error(log);
}
}Database Integration
import { Database } from "bun:sqlite";
const db = new Database("app.db", { create: true });
db.run(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
const insert = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
insert.run("Alice", "alice@example.com");
insert.run("Bob", "bob@example.com");
const users = db.query("SELECT * FROM users").all();
console.log(users);Bun's SQLite binding is a thin wrapper around SQLite with zero overhead—it doesn't serialize/deserialize results through JSON. Instead, Bun reads SQLite's internal representation directly and converts to JavaScript objects using a custom column reader. This makes queries 3-5x faster than better-sqlite3 for result sets with many rows.
Real-World Use Cases
CI/CD Pipeline Acceleration
A team with a 200-package monorepo replaced npm with Bun in their CI pipeline. bun install --frozen-lockfile went from 45 seconds (npm) to 3 seconds (Bun), saving 42 seconds per CI run. With 200 CI runs per day, this saved 2.3 hours of CI time daily and reduced their CI costs by 15%.
Serverless Cold Start Optimization
A serverless function running on AWS Lambda switched from Node.js to Bun. Cold start time dropped from 800ms to 120ms, and warm execution time improved by 30%. The lower memory footprint also allowed the team to reduce the Lambda memory allocation from 1024MB to 512MB, cutting costs by 50%. Bun's smaller runtime memory footprint (18MB idle vs Node.js's 42MB) makes it particularly well-suited for serverless environments where you pay per GB-second.
Development Workflow Speed
A Next.js development team switched their local development environment to Bun. bun install went from 28 seconds (npm) to 1.2 seconds, and bun run dev started the dev server 40% faster. The team reported that the faster iteration cycle improved their productivity noticeably—changes appeared in the browser almost instantly.
Cross-Platform Team Collaboration
A team with developers on macOS, Linux, and Windows standardized on Bun 1.1. The native Windows support eliminated WSL-related issues that had plagued the Windows developers. The single bun.lockb lockfile worked identically across all three platforms, and the deterministic dependency resolution meant that bun install --frozen-lockfile produced byte-identical node_modules directories on all platforms.
Build Pipeline Replacement
A React application replaced Webpack with Bun's built-in bundler. Build time dropped from 45 seconds to 2.8 seconds. While Bun's bundler doesn't support every Webpack plugin, it covers the common case of bundling a React SPA with code splitting, CSS modules, and asset handling. The team maintained a Webpack config for production builds but used Bun's bundler for development, where the 16x speed improvement was transformative.
Best Practices for Production
-
Use
--frozen-lockfilein CI — Prevents lockfile modifications during CI runs and fails fast if the lockfile is out of date. -
Enable strict TypeScript checking — Bun doesn't type-check at runtime. Run
tsc --noEmitas a separate CI step to catch type errors. -
Test with Node.js compatibility flags — Some Node.js APIs have subtle behavioral differences. Test critical paths with both runtimes if supporting both.
-
Use
Bun.serve()for HTTP servers — It's optimized for Bun's runtime and avoids the overhead of Node.js compatibility layers used by Express. -
Monitor memory usage — Bun's garbage collector (WebKit's Riptide GC) behaves differently from V8's Orinoco GC. Riptide uses a concurrent, generational, compacting collector that prioritizes low pause times. Profile memory usage under load to ensure no unexpected growth, especially in long-running processes.
-
Use
bun patchfor dependency fixes — Instead of forking dependencies or usingpatch-package, usebun patchwhich is built into the package manager. -
Commit both lockfile formats — If your team needs to review lockfile changes in PRs, use
--save-text-lockfileto generate a human-readable lockfile alongside the binary one. -
Use Docker multi-stage builds — Separate dependency installation from application build to leverage Docker layer caching with Bun's fast installs.
Common Pitfalls and Solutions
| Pitfall | Impact | Solution |
|---|---|---|
| Native Node.js addons fail | Build errors or runtime crashes | Use Bun's native bindings or pure JS alternatives |
| Subtle API behavior differences | Bugs in edge cases | Test critical paths with both runtimes |
| Windows path handling issues | File not found errors | Use path.join() consistently, avoid hardcoded separators |
| Worker thread limitations | Threading bugs | Test worker-heavy code thoroughly on Bun |
| Binary lockfile review difficulty | Hard to audit PRs | Use --save-text-lockfile for reviewable lockfiles |
| Different GC behavior | Memory leaks in long-running processes | Profile with bun --inspect and monitor RSS growth |
Missing node: prefix | Module resolution errors | Always use node:fs, node:path etc. explicitly |
Performance Optimization
Benchmark: Package Installation
| Project Size | npm install | bun install | Speedup |
|---|---|---|---|
| 50 deps | 8.2s | 0.3s | 27x |
| 200 deps | 28s | 1.1s | 25x |
| 500 deps | 65s | 2.8s | 23x |
| 1000 deps | 142s | 5.2s | 27x |
Benchmark: HTTP Server
| Metric | Node.js (http) | Bun.serve() | Speedup |
|---|---|---|---|
| Requests/sec | 68,000 | 190,000 | 2.8x |
| Latency (p99) | 2.4ms | 0.8ms | 3x |
| Memory (idle) | 42MB | 18MB | 2.3x |
| Cold start | 85ms | 12ms | 7x |
Benchmark: File I/O
| Operation | Node.js (fs) | Bun.file() | Speedup |
|---|---|---|---|
| Read 1MB file | 0.8ms | 0.1ms | 8x |
| Write 1MB file | 1.2ms | 0.3ms | 4x |
| Read 1000 small files | 120ms | 15ms | 8x |
| Glob scan 10K files | 450ms | 42ms | 10x |
Comparison with Alternatives
| Feature | Bun 1.1 | Node.js 22 | Deno 1.42 |
|---|---|---|---|
| Windows native | Yes | Yes | Yes |
| TypeScript native | Yes | Experimental (strip-only) | Yes |
| Package manager | Built-in | npm/yarn/pnpm | Built-in (URL-based) |
| Test runner | Built-in (Jest-compatible) | Built-in (node:test) | Built-in (Deno.test) |
| Bundler | Built-in | No | No |
| Node.js compat | ~90% | 100% | ~75% |
| Install speed | Fastest | Slow | Medium |
| Maturity | Growing | Very mature | Growing |
| Binary size | 45MB | 80MB | 110MB |
| Memory idle | 18MB | 42MB | 35MB |
Advanced Patterns
Bun with Docker
FROM oven/bun:1.1 AS base
WORKDIR /app
FROM base AS deps
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile --production
FROM base AS build
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN bun build ./src/index.ts --outdir ./dist --target=node
FROM base AS production
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER bun
EXPOSE 3000
CMD ["bun", "run", "dist/index.js"]Monorepo Configuration
{
"name": "monorepo",
"workspaces": ["packages/*", "apps/*"],
"scripts": {
"dev": "bun run --filter './apps/*' dev",
"build": "bun run --filter './packages/*' build",
"test": "bun test --filter './packages/*'"
}
}Bun Shell Scripting
Bun 1.1 includes a built-in shell (Bun.Shell) that lets you write shell scripts in JavaScript with cross-platform compatibility:
import { $ } from "bun";
// Run shell commands with automatic escaping
const files = await $`ls -la`.text();
// Chain commands
await $`mkdir -p dist && cp -r src/*.ts dist/`;
// Use JavaScript variables safely
const dir = "my-app";
await $`mkdir -p ${dir}`;The shell uses Bun's built-in process spawning and doesn't depend on /bin/sh, making scripts portable across Windows, macOS, and Linux without WSL or Git Bash.
Bun's Built-in SQLite
One of Bun's unique features is a built-in SQLite driver that's faster than any npm-based alternative. Bun's bun:sqlite module provides a synchronous, high-performance interface to SQLite databases without requiring better-sqlite3 or any native addon compilation.
import { Database } from "bun:sqlite";
const db = new Database("app.db", { create: true });
db.run(`
CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
completed INTEGER DEFAULT 0,
created_at TEXT DEFAULT (datetime('now'))
)
`);
const insert = db.prepare("INSERT INTO todos (title) VALUES (?)");
const select = db.prepare("SELECT * FROM todos WHERE completed = ?");
const insertMany = db.transaction((todos: string[]) => {
for (const title of todos) {
insert.run(title);
}
});
insertMany(["Buy groceries", "Write tests", "Deploy to production"]);
const pending = select.all(0);
console.log(`Pending todos: ${pending.length}`);The built-in SQLite driver is particularly valuable for local-first applications, CLI tools, and development servers that need a lightweight persistent store without the overhead of a full database server. Combined with Bun's file I/O performance, SQLite operations in Bun are significantly faster than equivalent operations in Node.js.
Testing Strategies
import { describe, test, expect, mock } from "bun:test";
describe("UserService", () => {
test("creates user with valid data", async () => {
const db = new Database(":memory:");
db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)");
const service = new UserService(db);
const user = await service.create({ name: "Alice", email: "alice@test.com" });
expect(user.id).toBeDefined();
expect(user.name).toBe("Alice");
});
test("rejects duplicate email", async () => {
const db = new Database(":memory:");
db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT UNIQUE)");
const service = new UserService(db);
await service.create({ name: "Alice", email: "alice@test.com" });
expect(service.create({ name: "Bob", email: "alice@test.com" })).rejects.toThrow();
});
});Bun's test runner is Jest-compatible by default—it recognizes describe, test, expect, and jest.fn() without configuration. Tests run in the same process as the runtime, eliminating the overhead of spawning separate Node.js processes for each test file. For a test suite with 500 files, this can reduce total test time from 45 seconds (Jest on Node.js) to 8 seconds (Bun).
Future Outlook
Bun's trajectory is clear: become the default JavaScript runtime for new projects. The 1.1 release removed the biggest adoption barriers (Windows support, Node.js compatibility), and future releases will continue closing the remaining gaps. The Bun team has signaled that they're targeting 95%+ Node.js compatibility by the end of 2025.
The broader JavaScript ecosystem is converging on a set of common APIs (WinterCG), which means code written for Bun will increasingly work on Node.js and Deno. This interoperability reduces the risk of adopting Bun—you're not locking yourself into a proprietary platform.
Looking ahead, Bun 1.2 introduced S3 file storage, built-in Postgres and MySQL clients, and further performance improvements. The runtime continues to absorb functionality that previously required separate npm packages, reducing the surface area of project dependencies and the attack surface for supply chain vulnerabilities.
Bun's roadmap focuses on achieving complete Node.js API compatibility while maintaining its performance leadership, making it an increasingly viable drop-in replacement for Node.js in production environments.
Conclusion
Bun 1.1 is the release that makes Bun a serious contender for production workloads. The key takeaways:
- Windows support removes the biggest barrier — Teams with Windows developers can now adopt Bun without WSL workarounds
- Node.js compatibility is production-ready — 90% compatibility means most applications run without modification
- Performance gains are real and measurable — 25x faster installs, 2.8x faster HTTP serving, 7x faster cold starts
bun patchandbun auditare quality-of-life wins — Built-in dependency patching and security scanning reduce tool sprawl- Start with non-critical services — Migrate CI pipelines, internal tools, and development environments first, then expand to production services
Install Bun 1.1 today with curl -fsSL https://bun.sh/install | bash and run bun install on your largest project. The speed improvement alone justifies the switch for development workflows.