Bun 1.1 — Windows Support

Bun 1.1 ships Windows support alongside 1,700 commits of Node.js compatibility fixes, a cross-platform shell, and a thousand bug fixes.

Bun 1.1 — Windows Support

Cross-platform support is not a compiler flag you flip. Windows has different path separators, no shebang support, unreliable symlinks, and a package manager ecosystem that produces .cmd, .sh, and .ps1 permutations for every binary. A runtime that claims Windows support without addressing those specifics is just a runtime that boots on Windows.

Source

Bun 1.1

By: Jarred Sumner, Chloe, Ashcon, Dylan, Meghan, Georgijs & Ciro
Published: Apr 01 2024
Type: Release notes

Saved because Windows support in a non-Node.js runtime is an underrated compatibility signal — the engineering decisions required to get there reveal exactly how deep the Node.js compatibility work actually goes.

The Engineering Cost of Real Cross-Platform Support

The .bunx file format is the clearest sign of how seriously Bun took Windows. Symlinks are unreliable on Windows, shebangs are not read, and maintaining three permutations of every binary — .cmd, .sh, .ps1 — is the kind of friction that accumulates into a slow, fragile toolchain. The team designed a new file format instead of patching three broken conventions. The result is bun run running 11x faster than npm run on Windows, with no “Terminate batch job?” prompts on ctrl-c. bun install is 18x faster than Yarn and 30x faster than npm on Windows for a Vite React app. These are not marketing benchmarks tuned on ideal conditions — they come from picking the right Windows syscalls per operation rather than routing everything through a cross-platform abstraction layer.

The Bun Shell fills the scripting gap that Windows has always had in the JavaScript ecosystem. rm -rf, FOO=bar <command>, and which simply do not work in Windows cmd. The Shell is a full lexer, parser, and interpreter for a bash-like language, exposed as Bun.$ in TypeScript. Variables passed into shell expressions are escaped by default — $\ls ${filename}`wherefilenameis“foo.js; rm -rf /”raises an error rather than executing the injection. Lifecycle scripts inbun installuse the Bun Shell on Windows, which meansrimraf, cross-env, and node-which` shims are no longer required in postinstall scripts.

Beyond Windows, 1.1 shipped several standard library APIs that replace popular npm packages. Bun.Glob matches strings 3x faster than fast-glob. Bun.Semver.satisfies() is 20x faster than node-semver. Bun.stringWidth() is 6000x faster than the npm string-width package — a number that sounds implausible until you remember that string-width is pure JavaScript counting graphemes in a loop, while native code handles it trivially. These are not capabilities added for their own sake; they eliminate common install-time dependencies that exist only because the runtime did not expose them.

Node.js compatibility saw significant depth. Date.parse() now uses a port of V8’s date parser, eliminating a class of silent failures where dates that parsed correctly in Node.js returned Invalid Date in Bun. WebSocket moved from experimental to stable after passing the full Autobahn conformance suite, fixing fragmentation and early-disconnect bugs. IPC between Bun and Node.js processes works bidirectionally, which also fixed a hanging bug in Next.js 14.1. The recursive option in fs.readdir() arrived and is 22x faster than Node.js. HTTP/2 client support means packages like @grpc/grpc-js work without modification.

Two behavioral changes require attention before upgrading. First, NODE_ENV defaults to undefined instead of "development" — aligning with Node.js but breaking any project that relied on the implicit value. Second, Bun.$ now rejects when a subprocess exits with a non-zero code. In Bun 1.0 the promise resolved silently on failure, which masked shell errors. The fix matches shell semantics, but pipelines that deliberately allow failure need .throws(false) added. Both changes are correct, and both will catch assumptions that were already bugs waiting to surface.

The trustedDependencies system in bun install introduces an explicit opt-in for lifecycle scripts. Packages outside the default allowlist have their postinstall scripts blocked at install time. bun pm untrusted shows what was blocked; bun pm trust runs it. This is a meaningful security posture change from npm — the tradeoff is that first-run workflows that depend on postinstall (native addons, binary downloads) require an extra step. bun add --trust makes the common case ergonomic by adding the package and its transitive dependencies to trustedDependencies in one command.

What I want to remember

Remember: .bunx is not just a convenience format — it is the reason Windows lifecycle scripts, bunx, and bun run work coherently without platform-specific shims, and it only exists because the team refused to treat three broken conventions as acceptable.