Skip to content

Bun Node.js Compatibility

One of Bun's design goals is compatibility with the Node.js ecosystem. This chapter introduces Bun's Node.js compatibility and migration guide.

Compatibility Overview

Supported Node.js APIs

Bun supports most Node.js core modules:

ModuleCompatibilityDescription
fs✅ CompleteFile system
path✅ CompletePath operations
http✅ MostHTTP server and client
https✅ MostHTTPS support
crypto✅ MostCryptographic functions
buffer✅ CompleteBuffer operations
stream✅ MostStream processing
events✅ CompleteEvent emitter
util✅ MostUtility functions
os✅ CompleteOperating system info
child_process✅ MostChild processes
worker_threads✅ MostWorker threads
net✅ MostNetwork sockets
dns✅ MostDNS resolution
url✅ CompleteURL processing
querystring✅ CompleteQuery string
zlib✅ MostCompression
assert✅ CompleteAssertions

Partially Supported APIs

ModuleStatusDescription
cluster⚠️ PartialLimited cluster mode support
vm⚠️ PartialLimited VM module support
inspector⚠️ PartialDebugger support
trace_events❌ UnsupportedTrace events
v8❌ UnsupportedV8 specific APIs

Using Node.js APIs

Import Methods

typescript
// Recommended: use node: prefix
import fs from "node:fs";
import path from "node:path";
import { EventEmitter } from "node:events";

// Also supported: without prefix
import crypto from "crypto";
import http from "http";

File System

typescript
import fs from "node:fs";
import { readFile, writeFile } from "node:fs/promises";

// Synchronous read
const content = fs.readFileSync("./file.txt", "utf-8");

// Async read
const asyncContent = await readFile("./file.txt", "utf-8");

// Write file
await writeFile("./output.txt", "Hello, Bun!");

// Stream read
const stream = fs.createReadStream("./large-file.txt");
for await (const chunk of stream) {
  console.log(chunk);
}

HTTP Server

typescript
import http from "node:http";

// Node.js style HTTP server
const server = http.createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "text/plain" });
  res.end("Hello from Node.js API!");
});

server.listen(3000, () => {
  console.log("Server running at http://localhost:3000");
});

Child Processes

typescript
import { spawn, exec } from "node:child_process";

// Use spawn
const child = spawn("ls", ["-la"]);

child.stdout.on("data", (data) => {
  console.log(`stdout: ${data}`);
});

// Use exec
exec("echo 'Hello'", (error, stdout, stderr) => {
  if (error) {
    console.error(`Error: ${error}`);
    return;
  }
  console.log(`Output: ${stdout}`);
});

// Use Promise (recommended)
import { execSync } from "node:child_process";
const result = execSync("echo 'Hello'").toString();

Cryptography

typescript
import crypto from "node:crypto";

// Hash
const hash = crypto.createHash("sha256")
  .update("Hello, World!")
  .digest("hex");
console.log("SHA256:", hash);

// HMAC
const hmac = crypto.createHmac("sha256", "secret")
  .update("message")
  .digest("hex");

// Random bytes
const randomBytes = crypto.randomBytes(16);
console.log("Random bytes:", randomBytes.toString("hex"));

// UUID
const uuid = crypto.randomUUID();
console.log("UUID:", uuid);

Migrating from Node.js

Step 1: Install Bun

bash
# Install Bun
curl -fsSL https://bun.sh/install | bash

# Verify installation
bun --version

Step 2: Switch Package Manager

bash
# Remove old dependencies
rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml

# Install with Bun
bun install

Step 3: Update package.json

json
{
  "scripts": {
    "start": "bun src/index.ts",
    "dev": "bun --watch src/index.ts",
    "build": "bun build src/index.ts --outdir dist",
    "test": "bun test"
  }
}

Step 4: Check Compatibility

bash
# Try running
bun src/index.ts

# Check for errors

Common Migration Issues

Issue 1: Module Not Found

typescript
// ❌ May throw error
import { something } from "obscure-package";

// ✅ Check package compatibility
bun pm ls obscure-package

Issue 2: Native Modules

typescript
// Some native Node.js modules may not be compatible
// Need to find alternatives or wait for Bun support

// For example: sharp image processing
// Check Bun support: https://bun.sh/docs/ecosystem

Issue 3: Node.js Specific APIs

typescript
// ❌ Some Node.js specific APIs may not exist
process.binding("buffer");

// ✅ Use standard API alternatives
import { Buffer } from "node:buffer";

Issue 4: __dirname and __filename

typescript
// In ESM, __dirname and __filename are not available

// ✅ Bun supports these
console.log(__dirname);  // Available
console.log(__filename); // Available

// Or use import.meta
console.log(import.meta.dir);  // Directory
console.log(import.meta.path); // File path

Bun vs Node.js API Comparison

File Operations

typescript
// Node.js
import { readFile } from "fs/promises";
const content = await readFile("./file.txt", "utf-8");

// Bun (more concise)
const content = await Bun.file("./file.txt").text();

HTTP Server

typescript
// Node.js
import http from "http";
const server = http.createServer((req, res) => {
  res.writeHead(200);
  res.end("Hello");
});
server.listen(3000);

// Bun (more concise)
Bun.serve({
  port: 3000,
  fetch: () => new Response("Hello"),
});

Environment Variables

typescript
// Node.js
require("dotenv").config();
const value = process.env.MY_VAR;

// Bun (auto loads .env)
const value = Bun.env.MY_VAR;
// or
const value = process.env.MY_VAR;

Running TypeScript

bash
# Node.js
npx ts-node app.ts
# or
npx tsx app.ts

# Bun (direct run)
bun app.ts

Using Bun Alternatives

Replacing Express

typescript
// Use Elysia (Bun-specific framework)
import { Elysia } from "elysia";

const app = new Elysia()
  .get("/", () => "Hello Elysia")
  .get("/user/:id", ({ params: { id } }) => `User ${id}`)
  .post("/user", ({ body }) => body)
  .listen(3000);

console.log(`Running at http://localhost:${app.server?.port}`);

Replacing Jest

typescript
// Bun built-in testing
import { test, expect } from "bun:test";

test("addition", () => {
  expect(1 + 1).toBe(2);
});

Replacing webpack/esbuild

typescript
// Bun built-in bundling
await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  minify: true,
});

Progressive Migration

Strategy 1: Partial Bun Usage

json
{
  "scripts": {
    "start": "node dist/index.js",
    "dev": "bun --watch src/index.ts",
    "test": "bun test",
    "build": "bun build src/index.ts --outdir dist"
  }
}

Strategy 2: Conditional Usage

typescript
// Detect runtime
const isBun = typeof Bun !== "undefined";

if (isBun) {
  // Use Bun API
  const content = await Bun.file("./data.txt").text();
} else {
  // Use Node.js API
  const { readFile } = await import("fs/promises");
  const content = await readFile("./data.txt", "utf-8");
}

Strategy 3: Abstraction Layer

typescript
// file-utils.ts
export async function readTextFile(path: string): Promise<string> {
  if (typeof Bun !== "undefined") {
    return Bun.file(path).text();
  }
  const { readFile } = await import("fs/promises");
  return readFile(path, "utf-8");
}

Compatibility Check Tools

Check Package Compatibility

bash
# View package compatibility status
# Visit https://bun.sh/ecosystem

Test Run

bash
# Run project and observe errors
bun run start 2>&1 | head -50

# Run tests
bun test

Known Limitations

Incompletely Supported Features

  1. cluster module: Limited support
  2. vm module: Partial functionality
  3. Some Node.js internal APIs
  4. Specific native modules

Solutions

typescript
// If you encounter unsupported features
// 1. Check Bun docs for alternatives
// 2. Use polyfills
// 3. Conditional loading
// 4. Wait for Bun updates

// Example: conditional cluster usage
if (typeof Bun !== "undefined") {
  // Use Bun's multi-process solution
} else {
  // Use Node.js cluster
  const cluster = require("cluster");
  // ...
}

Summary

This chapter covered:

  • ✅ Bun's compatibility with Node.js APIs
  • ✅ How to use Node.js modules
  • ✅ Steps to migrate from Node.js
  • ✅ Common migration issues and solutions
  • ✅ Bun alternatives
  • ✅ Progressive migration strategies

Next Steps

Continue reading Learning Resources for more learning materials.

Content is for learning and research only.