跪拜 Guibai
← Back to the summary

Bun 1.2 Replaces Node.js Tooling in 20 Minutes: Install Speeds Jump 15x, Tests Run 3x Faster

If your project takes a minute for every npm install, over ten seconds for each test run, and leaves you staring at the terminal waiting for the dev server to start — you should try Bun. This article skips the hype and directly migrates a real project from Node.js to Bun, laying out the migration steps, the pitfalls encountered, and whether it's right for your project.

What is Bun, and why try it in 2026

If you don't know Bun yet — it's a JavaScript runtime written in Zig, designed as a drop-in replacement for Node.js.

Its relationship to Node.js can be summed up in one sentence:

Bun is to Node.js what Vite is to Webpack — it does the same job, but much faster.

It's not just a runtime, but an all-in-one toolkit:

Function Node.js Ecosystem Bun Built-in
Runtime Node.js Bun
Package Manager npm / pnpm / yarn bun install
Bundler Webpack / Vite / esbuild bun build
Test Framework Jest / Vitest bun test
TypeScript Requires ts-node / tsx Native support, runs .ts directly
.env Loading Requires dotenv package Native support

By 2026, Bun has reached version 1.2+, and its stability is far better than two years ago. Most npm packages work out of the box.


Before-and-after migration data

Both Bun's official benchmarks and community tests point to the same conclusion: it's fast, and not just by a little.

Using a medium-sized full-stack project (React + Express, roughly 200 npm dependencies) as a reference:

Operation Node.js 20 + npm Bun 1.2 Difference
install (no cache) ~40-60s ~3-5s 10-15x
install (cached) ~10-15s < 1s 20x+
Dev server start ~5-10s ~1-3s 3-5x
Unit tests (100+ cases) ~10-15s ~3-5s 3x
TypeScript compilation Requires extra ts-node config Native support
Cold start an HTTP endpoint ~200-400ms ~50-100ms 3-4x

Specific numbers depend on your machine and project size, but the order-of-magnitude gap is consistent. You can run a comparison on your own project to see.


Migration steps (get it done in 20 minutes)

Step 1: Install Bun

# macOS / Linux
curl -fsSL https://bun.sh/install | bash

# Verify installation
bun --version
# 1.2.x

Windows users should install via WSL2. Bun's native Windows support is largely complete as of version 1.2.

Step 2: Replace npm with Bun

# Delete node_modules and lock files
rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml

# Reinstall dependencies with Bun
bun install

This step generates bun.lockb (Bun's lock file, a binary format much faster than JSON).

Step 3: Replace scripts in package.json

{
  "scripts": {
    "dev": "bun run --hot src/server.ts",
    "build": "bun build src/index.ts --outdir dist",
    "test": "bun test",
    "start": "bun src/server.ts"
  }
}

Key changes:

Step 4: Run the tests

bun test
bun run dev

Most projects will run fine at this point. If you hit issues, check the pitfall records below.


Pitfall records

Pitfall 1: Some Node.js native modules are incompatible

My project used bcrypt (password hashing), which is a C++ native addon. Bun supports most native addons now, but a specific version of bcrypt had issues.

Solution: Switch to the pure JS implementation bcryptjs.

bun remove bcrypt
bun add bcryptjs

The only code change is the import path:

// Before
import bcrypt from 'bcrypt';

// After
import bcrypt from 'bcryptjs';

The API is identical; no business logic changes needed. The performance gap is negligible in most scenarios.

General principle: If a package has both a C++ native addon version and a pure JS version, prefer the pure JS version when migrating to Bun.

Pitfall 2: __dirname and __filename behavior differences

Bun supports __dirname and __filename, but in ES Module mode, the behavior differs slightly from Node.js.

If your code has this pattern:

import path from 'path';
const configPath = path.join(__dirname, '../config/default.json');

It might error out in Bun's ESM mode.

Solution: Use import.meta instead.

import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const configPath = path.join(__dirname, '../config/default.json');

This approach is compatible with both Node.js and Bun.

Pitfall 3: .env no longer needs dotenv

Bun natively supports .env file loading, so the dotenv package is unnecessary.

If your code contains:

import 'dotenv/config';
// or
require('dotenv').config();

You can delete that line in Bun. Bun automatically loads the .env file from the project root.

But note: If you have both .env and .env.local, Bun's loading priority differs from dotenv. Bun's priority is:

.env.local > .env.production / .env.development > .env

Advice: After migration, double-check that all environment variables are loaded correctly.

Pitfall 4: Syntax differences between bun test and Jest

bun test's API is largely compatible with Jest, but there are a few differences:

// Jest syntax (also works in Bun)
expect(fn).toHaveBeenCalledWith(expect.objectContaining({ id: 1 }));

// But this Jest-specific mocking method is not supported:
jest.mock('./database');

// Bun's mocking method:
import { mock } from 'bun:test';
mock.module('./database', () => ({
  query: mock(() => Promise.resolve([]))
}));

Solution: If your tests rely heavily on jest.mock, consider keeping Vitest or Jest for testing for now, and using Bun for everything else. Bun can coexist with existing test frameworks.


Which scenarios are suitable for migration, and which are not

Scenario Recommended? Reason
Personal project / side project ✅ Strongly recommended No legacy baggage, enjoy the speed immediately
New project ✅ Recommended Start from scratch with Bun, avoid migration costs
Small to medium full-stack project ✅ Yes Most npm packages are compatible
Large enterprise project ⚠️ Proceed with caution Many native addons, CI/CD needs adaptation
Heavy native addon dependency ❌ Not recommended for now sharp, canvas, etc. may have compatibility issues
Serverless / Edge deployment ✅ Recommended Bun's cold start is extremely fast, ideal for serverless

Migration checklist

Use this checklist to confirm the migration is complete:


Packages you can uninstall after migration

After migrating to Bun, these packages can be removed directly:

bun remove dotenv ts-node tsx nodemon ts-jest
Package Reason
dotenv Bun natively supports .env
ts-node / tsx Bun runs TypeScript natively
nodemon bun run --hot has built-in hot reload
ts-jest bun test natively supports TypeScript

With fewer dependencies, node_modules shrinks a bit more.


Final thoughts

Migrating the whole project took about 20 minutes, and fixing pitfalls added up to just over an hour.

What you get in return is installs that are over ten times faster, startup that is several times faster, and tests that run 3x faster in your daily development. Once you experience this speed gap, there's no going back.

If you're still hesitating, start by trying it on a side project. A 20-minute migration cost with almost zero risk.

What runtime and package manager does your project currently use? Have you considered migrating to Bun? Let's discuss in the comments.