DEV Community

Alex Cloudstar
Alex Cloudstar

Posted on • Originally published at alexcloudstar.com

Bun Compatibility in 2026: What Actually Works, What Does Not, and When to Switch

Bun hit v1.0 in September 2023. It is now well into its production era. And yet "is Bun production ready 2026" is still a common search -- because "ready" means completely different things depending on your stack.

Ready for a CLI tool written in TypeScript? Absolutely, day one. Ready as a Next.js runtime for an app that uses sharp and bcrypt? The answer is more complicated and it changes by package.

This article is the compatibility map. Not benchmarks (that is covered in the Bun vs Node.js deep dive), not philosophy -- just the practical 2026 state of what works, what breaks, and what the failure mode looks like when it does break.


Node.js API Compatibility: The Current State

Bun implements the Node.js API surface, but not all of it, and some parts behave slightly differently. Here is where things stand in 2026.

The core built-ins: solid

The APIs you use every day work:

  • node:fs and node:fs/promises -- full compatibility, Bun's file I/O is actually faster
  • node:path, node:url, node:os -- complete
  • node:http and node:https -- implemented and compatible with Express, Fastify, and most HTTP frameworks
  • node:crypto -- mostly complete; some edge cases remain around specific cipher suites and legacy methods
  • node:stream -- largely implemented; occasional edge cases with transform streams in unusual configurations
  • node:buffer -- full compatibility
  • node:process -- complete, including process.env, process.argv, process.exit

For the vast majority of Node.js code, you can run it on Bun unchanged.

The more specialized APIs: mixed

node:worker_threads -- implemented and usable. Performance characteristics differ because Bun uses JavaScriptCore instead of V8. For CPU-bound parallelism, worker threads work. Test your specific workload rather than assuming the behavior is identical.

node:cluster -- partial support as of 2026. Basic cluster forking works, but some of the more advanced cluster coordination patterns have edge cases. If your production server relies heavily on Node.js cluster for multi-process load balancing, test carefully before switching.

node:child_process -- solid. spawn, exec, execFile, and fork all work. The fork method has some nuances in how it communicates with child processes, but for most use cases it is fine.

node:vm -- partial and fragile. If you are using vm.Script or vm.runInNewContext for sandboxing or dynamic code evaluation, this is an area to verify specifically.

Native addons: the main real-world blocker

This is where Bun compatibility actually breaks down, and it is worth understanding why.

Node.js native addons are C/C++ extensions compiled to binary using node-gyp or N-API. They produce .node files that V8 loads directly. Bun uses JavaScriptCore, not V8, so these binaries are incompatible at a fundamental level -- they are compiled against V8's internal structures.

Packages this affects:

  • bcrypt -- uses native bindings, does not work. Use bcryptjs (pure JavaScript drop-in) or Bun's built-in Bun.password API instead
  • canvas -- native addon, broken on Bun. No clean workaround if you need full canvas support
  • better-sqlite3 -- native addon, but Bun has a built-in SQLite API (bun:sqlite) that is faster and requires no native bindings at all
  • sharp -- this one improved significantly. Sharp added libvips-based builds that work through WebAssembly fallback, so it works on Bun in 2026 in most configurations. Verify your platform and version.
  • argon2 -- native addon; similar to bcrypt, check for a pure-JS or Bun-native alternative

The practical check: search your-package node-gyp or look at the package's binding.gyp file. If it has one, it is a native addon and Bun will not run it.

Bun's own APIs: the portability tradeoff

Bun ships fast native replacements for common operations:

// Bun-native file reading -- faster than fs.readFile
const file = Bun.file('./data.json');
const data = await file.json();

// Bun-native HTTP server -- outperforms http.createServer significantly
Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response('ok');
  },
});
Enter fullscreen mode Exit fullscreen mode

These are genuinely fast. The tradeoff is portability -- code using Bun.serve or Bun.file does not run on Node.js without changes. Whether that matters depends on whether you ever need to deploy to a Node.js environment or whether Bun is your permanent runtime choice.


npm Package Compatibility: the Practical Picture

The install story is mostly a non-story now. bun install reads your package.json, installs from the npm registry, and is dramatically faster than npm. The compatibility question is not about installation -- it is about what happens at runtime.

Pure JavaScript and TypeScript packages: just works

If a package is pure JavaScript or TypeScript (no native bindings), it runs on Bun. This covers the overwhelming majority of the npm ecosystem:

  • React, Vue, Svelte -- yes
  • Zod, Valibot, TypeBox -- yes
  • Lodash, date-fns, Ramda -- yes
  • Axios, got, ky, node-fetch -- yes
  • Prisma Client -- yes (Prisma works well on Bun since v5.4; the generated client is pure JavaScript)
  • Drizzle ORM -- yes
  • Express, Fastify, Hono, Elysia -- yes
  • Jest (sort of -- Bun has its own test runner, but jest itself can run)
  • TypeScript itself, ts-node, tsx -- yes, and largely unnecessary since Bun runs TypeScript natively

Packages with postinstall scripts: sometimes messy

Some packages run scripts after installation to download platform-specific binaries or perform setup. These usually work, but occasionally fail if the script assumes Node.js behaviors. The failure is almost always visible during bun install as a warning or error -- it does not silently break.

puppeteer and playwright are common examples. They download browser binaries in postinstall. These generally work but can be slow or require manual intervention in certain CI environments.

Packages using node-gyp or native compilation

Covered above under Node.js API compatibility. These are the packages to audit before committing to Bun.

A quick way to check your project's exposure:

# List packages with native bindings in your dependency tree
bun pm ls | xargs -I{} sh -c 'ls node_modules/{}/binding.gyp 2>/dev/null && echo {}'
Enter fullscreen mode Exit fullscreen mode

Or just run bun install and look for gyp-related warnings -- Bun will flag them.

Specific 2026 status for commonly used packages

Package Status Notes
Prisma Works Pure JS client, works since v5.4
Drizzle ORM Works No native deps
sharp Works (mostly) WebAssembly fallback; verify your build target
bcrypt Broken Use bcryptjs or Bun.password
better-sqlite3 Not needed Use bun:sqlite instead
canvas Broken No practical workaround
argon2 Broken Native addon; use argon2-browser or alternatives
pg (node-postgres) Works Pure JS driver
mysql2 Works Pure JS driver

Next.js + Bun: the Compatibility Story

This is the question people search most specifically, and the answer has two distinct parts that are easy to conflate.

Bun as the package manager for Next.js: yes, works great

Using bun install instead of npm install or yarn for a Next.js project is a straightforward win. Install times drop dramatically. Your node_modules are the same. Next.js does not know or care about what installed its packages.

# Works perfectly -- just replace npm with bun for installs
bun install
bun add some-package
bun remove old-package
Enter fullscreen mode Exit fullscreen mode

This is the low-risk first step for any Next.js project. No compatibility concerns, instant improvement in install speed.

Bun as the runtime for Next.js: more nuanced

Can you run bun next dev and bun next build? Yes. Does it work for most projects? Also yes. Does it work for all Next.js features? Not quite.

The key clarification first: Next.js compiles and runs through its own build pipeline. When you run bun next dev, Bun is executing the Next.js CLI, which then handles module loading and server-side rendering using its own bundler. You are not replacing the entire runtime with Bun's HTTP server.

What works reliably with Bun runtime + Next.js:

  • App Router and Pages Router
  • Server Components
  • API Routes (both App Router route handlers and Pages API)
  • Static generation and ISR
  • Middleware (with caveats -- see below)
  • Most npm packages in the Next.js context

Known gaps and caveats as of 2026:

Next.js Middleware runs on an edge-compatible runtime by default. When running through Bun, the edge runtime sandbox behavior can produce subtle differences from running on Node.js. If your middleware uses anything beyond basic request/response manipulation, test it explicitly.

Some @next/ packages and plugins that assume Node.js internals can behave differently. The main one to check is next-auth -- version 5 (Auth.js) works, but older v4 installations with certain adapters can hit edge cases.

Turbopack vs Bun's bundler -- clarifying the confusion

People sometimes search "Bun vs Turbopack" as if they are competing. They are not really alternatives in the Next.js context. Turbopack is Next.js's own incremental bundler for development (next dev --turbopack). Bun has its own bundler (bun build) for general JavaScript bundling outside of frameworks.

When you run Next.js with Bun, Turbopack is still handling the bundling if you enable it. Bun is handling the process execution and module resolution. They can coexist.

The practical recommendation:

For most Next.js projects in 2026, using Bun as the package manager is a safe, low-effort win. Using Bun as the full runtime is worth doing if you have tested your specific package set and want the startup time and performance improvements. The safe path is: bun install for package management, node for production runtime until you have explicitly validated your project.

For the TypeScript angle on running without a build step, the native type stripping in Node.js article covers how Node.js is closing this gap, which changes the calculus on Bun adoption for TypeScript projects specifically.


Where Bun Genuinely Wins in Production Today

There are categories where Bun is not just "ready" -- it is the better choice.

Standalone API servers and microservices without native addons. If you are building an HTTP API in TypeScript using Prisma, Drizzle, or a pure-JS database client, Bun is excellent. The startup time, memory footprint, and HTTP throughput are all better than Node.js. Hono on Bun is a particularly good pairing.

Scripts, CLIs, and build tooling. This is where Bun's startup speed advantage is most tangible. A script that starts in 40ms instead of 180ms feels snappy. Bun's native TypeScript execution means no compilation step for these tools. If you write any internal tooling, dev scripts, or CLI utilities in TypeScript, Bun should be your first choice.

Bun's test runner in CI. bun test is fast, Jest-compatible for basic assertions, and requires no configuration for TypeScript. For most projects, you can replace Jest with bun test and cut CI test times noticeably. The runner is mature enough for production CI pipelines.

# Drop-in for most Jest setups
bun test

# Watch mode for development
bun test --watch

# Run a specific file
bun test src/utils/helpers.test.ts
Enter fullscreen mode Exit fullscreen mode

Monorepo workspace management. Bun's workspace support has improved significantly. If you have a monorepo and are tired of waiting for npm or yarn installs across a large dependency graph, Bun's install speed is a genuine production-grade improvement.


Where You Should Still Stay on Node.js

Be honest with yourself about your project's needs.

You have native addon dependencies that do not have alternatives. If you are using canvas, certain image processing libraries, or any package where node-gyp is non-negotiable and there is no pure-JS equivalent, stay on Node.js. The workarounds are painful and not worth it.

Long-running production servers where you have years of operational knowledge. Node.js has a decade of production behavior that teams understand deeply. If your monitoring, profiling tools, and incident response playbooks are built around Node.js behavior, the cognitive overhead of switching a critical production service is a real cost.

Teams with limited capacity to debug surprises. Bun is not perfect. When it breaks, the error messages are sometimes less helpful than Node.js equivalents, and Stack Overflow coverage is thinner. If your team cannot absorb debugging time, the safe choice is still Node.js.

Anything relying on specific V8 behaviors. Bun uses JavaScriptCore. For 99% of code this is invisible. But there are edge cases around garbage collection timing, specific regex behaviors, and certain micro-benchmarking patterns that differ. If you have code that implicitly relies on V8's behavior (unusual but possible), Bun will surprise you.


How to Test Your Project's Bun Readiness

Do not decide based on general advice. Test your actual project. This takes about 30 minutes.

Step 1: Install Bun alongside Node.js

Bun and Node.js coexist without conflict. You keep your Node.js installation.

curl -fsSL https://bun.sh/install | bash
# or: npm install -g bun
Enter fullscreen mode Exit fullscreen mode

Step 2: Run bun install and read the output

bun install
Enter fullscreen mode Exit fullscreen mode

Look for gyp warnings, native compilation failures, and postinstall script errors. These are your blockers. Everything else is cosmetic.

Step 3: Run your test suite

bun test
Enter fullscreen mode Exit fullscreen mode

If you are using Jest, it will likely work directly. If some tests fail, look at whether the failures are genuine bugs or compatibility differences -- they usually fall into one of the patterns described above.

Step 4: Start your dev server

bun run dev
Enter fullscreen mode Exit fullscreen mode

Check that your routes work, your database connections initialize correctly, and your middleware behaves as expected. For Next.js, click through the main flows of your app.

Step 5: Check your postinstall scripts manually

Look in your package.json and each package's scripts for postinstall entries. If any download platform binaries or run build steps, verify they completed correctly.

Step 6: Run a quick native addon audit

# Find packages with binding.gyp in your node_modules
find node_modules -name "binding.gyp" -maxdepth 3 | sed 's|/binding.gyp||' | sed 's|node_modules/||'
Enter fullscreen mode Exit fullscreen mode

This gives you the list of native addon packages to evaluate individually.


The Verdict

The blanket "is Bun production ready" answer is: it depends on your stack, and now you have the map to check your specific case.

Use Bun today, confidently:

  • New TypeScript projects with no native addon requirements
  • CLI tools and internal scripts
  • Standalone APIs using Prisma, Drizzle, or pg
  • Monorepo package management
  • CI test runner replacement

Use Bun as the package manager, Node.js as the runtime:

  • Existing Next.js apps you want to migrate gradually
  • Projects where you have not audited the full dependency tree yet
  • Teams that want the install speed win without the runtime risk

Stay on Node.js for now:

  • Projects with hard native addon dependencies (canvas, argon2 without alternatives)
  • Production servers where operational stability is the top priority
  • Teams without bandwidth to debug compatibility surprises

For the performance side of this decision -- startup time, HTTP throughput, real-world benchmarks -- the Bun vs Node.js comparison has the numbers. This article is the compatibility map; that one is the performance case. Read both before you decide.

Top comments (0)