Bun is an ultra-fast JavaScript runtime and package manager written in Zig. In Bun 1.2, Node.js compatibility has significantly improved, accelerating enterprise adoption.
Major New Features in Bun 1.2
Overview
flowchart TB
subgraph Bun12["Bun 1.2"]
subgraph Compat["Node.js Compatibility"]
C1["node:cluster Full Support"]
C2["node:dgram (UDP) Support"]
C3["node:v8 Partial Support"]
C4["90%+ npm packages work"]
end
subgraph Features["New Features"]
F1["Built-in S3 Client"]
F2["Bun.color() Color Processing API"]
F3["Improved Watch Mode"]
F4["HTML/CSS Bundler"]
end
subgraph Perf["Performance"]
P1["HTTP Server: 30% faster"]
P2["Memory Usage: 20% reduction"]
P3["Package Install: 2x faster"]
end
end
Node.js Compatibility Improvements
node:cluster Support
// cluster-server.ts - Multi-process server
import cluster from 'node:cluster';
import { cpus } from 'node:os';
import { serve } from 'bun';
const numCPUs = cpus().length;
if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
console.log(`Forking ${numCPUs} workers...`);
// Fork workers for each CPU core
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
// Auto-restart
cluster.fork();
});
// Receive messages from workers
cluster.on('message', (worker, message) => {
console.log(`Message from worker ${worker.process.pid}:`, message);
});
} else {
// Worker process
const server = serve({
port: 3000,
fetch(req) {
return new Response(`Hello from worker ${process.pid}`);
},
});
console.log(`Worker ${process.pid} started on port ${server.port}`);
// Send message to primary
process.send?.({ status: 'ready', pid: process.pid });
}
node:dgram (UDP) Support
// udp-server.ts
import dgram from 'node:dgram';
const server = dgram.createSocket('udp4');
server.on('error', (err) => {
console.error(`Server error:\n${err.stack}`);
server.close();
});
server.on('message', (msg, rinfo) => {
console.log(`Server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
// Send response
const response = Buffer.from(`Received: ${msg}`);
server.send(response, rinfo.port, rinfo.address);
});
server.on('listening', () => {
const address = server.address();
console.log(`UDP server listening on ${address.address}:${address.port}`);
});
server.bind(41234);
// udp-client.ts
const client = dgram.createSocket('udp4');
const message = Buffer.from('Hello UDP Server');
client.send(message, 41234, 'localhost', (err) => {
if (err) {
console.error('Send error:', err);
client.close();
return;
}
console.log('Message sent');
});
client.on('message', (msg) => {
console.log(`Received: ${msg}`);
client.close();
});
Built-in S3 Client
Simplified S3 Operations
// Bun.s3 - Native S3 client
// Automatically get credentials from environment variables
// AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION
// File upload
const file = Bun.file('./large-file.zip');
await Bun.s3.write('my-bucket/uploads/large-file.zip', file);
// Streaming upload
const response = await fetch('https://example.com/large-video.mp4');
await Bun.s3.write('my-bucket/videos/video.mp4', response);
// Write text data
await Bun.s3.write(
'my-bucket/data/config.json',
JSON.stringify({ setting: 'value' }),
{ contentType: 'application/json' }
);
// Read file
const data = await Bun.s3.file('my-bucket/data/config.json').text();
const config = JSON.parse(data);
// Read as ArrayBuffer
const buffer = await Bun.s3.file('my-bucket/images/photo.jpg').arrayBuffer();
// Streaming read
const stream = Bun.s3.file('my-bucket/large-data.csv').stream();
// Get file info
const s3File = Bun.s3.file('my-bucket/document.pdf');
console.log({
exists: await s3File.exists(),
size: await s3File.size,
lastModified: await s3File.lastModified,
});
// Delete file
await Bun.s3.delete('my-bucket/temp/old-file.txt');
// Generate signed URL
const signedUrl = await Bun.s3.presign('my-bucket/private/file.pdf', {
expiresIn: 3600, // 1 hour
method: 'GET',
});
// List objects
for await (const object of Bun.s3.list('my-bucket/uploads/')) {
console.log(object.key, object.size, object.lastModified);
}
S3 File Server
// s3-file-server.ts
import { serve } from 'bun';
serve({
port: 3000,
async fetch(req) {
const url = new URL(req.url);
const path = url.pathname.slice(1); // Remove leading /
if (req.method === 'GET') {
// Stream file directly from S3
const s3File = Bun.s3.file(`my-bucket/${path}`);
if (!(await s3File.exists())) {
return new Response('Not Found', { status: 404 });
}
return new Response(s3File.stream(), {
headers: {
'Content-Type': s3File.type || 'application/octet-stream',
'Content-Length': String(await s3File.size),
},
});
}
if (req.method === 'PUT') {
// Stream request body to S3
await Bun.s3.write(`my-bucket/${path}`, req);
return new Response('Uploaded', { status: 201 });
}
if (req.method === 'DELETE') {
await Bun.s3.delete(`my-bucket/${path}`);
return new Response('Deleted', { status: 200 });
}
return new Response('Method Not Allowed', { status: 405 });
},
});
Bun.color() API
New Color Processing API
// Bun.color() - High-speed color processing
// Parse CSS color string
const red = Bun.color('red');
console.log(red); // { r: 255, g: 0, b: 0, a: 1 }
// Convert from HEX
const hex = Bun.color('#3498db');
console.log(hex); // { r: 52, g: 152, b: 219, a: 1 }
// Convert from RGB
const rgb = Bun.color('rgb(100, 150, 200)');
console.log(rgb); // { r: 100, g: 150, b: 200, a: 1 }
// Convert from HSL
const hsl = Bun.color('hsl(210, 60%, 50%)');
console.log(hsl); // { r: ..., g: ..., b: ..., a: 1 }
// Output as array
const [r, g, b, a] = Bun.color('#ff6b6b', 'array');
console.log(r, g, b, a); // 255, 107, 107, 1
// Convert to HEX string
const hexString = Bun.color({ r: 255, g: 100, b: 50, a: 1 }, 'hex');
console.log(hexString); // '#ff6432'
// Convert to CSS format
const cssRgb = Bun.color({ r: 255, g: 100, b: 50, a: 0.5 }, 'css');
console.log(cssRgb); // 'rgba(255, 100, 50, 0.5)'
// Color manipulation
function lighten(color: string, amount: number): string {
const { r, g, b, a } = Bun.color(color)!;
return Bun.color({
r: Math.min(255, r + amount),
g: Math.min(255, g + amount),
b: Math.min(255, b + amount),
a,
}, 'hex');
}
function darken(color: string, amount: number): string {
const { r, g, b, a } = Bun.color(color)!;
return Bun.color({
r: Math.max(0, r - amount),
g: Math.max(0, g - amount),
b: Math.max(0, b - amount),
a,
}, 'hex');
}
console.log(lighten('#3498db', 30)); // Lighter
console.log(darken('#3498db', 30)); // Darker
Improved Watch Mode
Enhanced File Watching
// bun --watch for dev server
// package.json
{
"scripts": {
"dev": "bun --watch src/index.ts",
"dev:hot": "bun --hot src/server.ts"
}
}
// --watch: Process restart
// --hot: Hot reload (preserves state)
// hot-reload-server.ts
import { serve } from 'bun';
// Global state (preserved during hot reload)
declare global {
var requestCount: number;
}
globalThis.requestCount ??= 0;
serve({
port: 3000,
fetch(req) {
globalThis.requestCount++;
return new Response(`
<html>
<body>
<h1>Hot Reload Demo</h1>
<p>Request count: ${globalThis.requestCount}</p>
<p>Last updated: ${new Date().toISOString()}</p>
</body>
</html>
`, {
headers: { 'Content-Type': 'text/html' },
});
},
});
console.log('Server started on port 3000');
Programmatic File Watching
// Bun.watch() - File watching API
const watcher = Bun.watch({
paths: ['./src'],
recursive: true,
filter: (path) => path.endsWith('.ts') || path.endsWith('.tsx'),
});
for await (const event of watcher) {
console.log(`${event.type}: ${event.path}`);
if (event.type === 'change' || event.type === 'create') {
// Handle file change
await runTests(event.path);
}
if (event.type === 'delete') {
// Handle file deletion
console.log(`File deleted: ${event.path}`);
}
}
async function runTests(changedFile: string) {
const testFile = changedFile.replace('.ts', '.test.ts');
if (await Bun.file(testFile).exists()) {
const proc = Bun.spawn(['bun', 'test', testFile]);
await proc.exited;
}
}
HTML Bundler
Simplified Frontend Builds
// bun build --html
// Input: index.html
// <!DOCTYPE html>
// <html>
// <head>
// <link rel="stylesheet" href="./styles.css">
// </head>
// <body>
// <div id="app"></div>
// <script type="module" src="./app.tsx"></script>
// </body>
// </html>
// Build command
// bun build ./index.html --outdir=./dist
// Result:
// - Auto-detect CSS/JS in HTML
// - Auto-compile TypeScript/TSX
// - Bundle and optimize CSS
// - Resolve dependencies
// Programmatic HTML build
const result = await Bun.build({
entrypoints: ['./src/index.html'],
outdir: './dist',
minify: true,
sourcemap: 'external',
splitting: true,
target: 'browser',
define: {
'process.env.NODE_ENV': '"production"',
},
loader: {
'.png': 'file',
'.svg': 'file',
'.woff2': 'file',
},
});
if (!result.success) {
console.error('Build failed:');
for (const log of result.logs) {
console.error(log);
}
process.exit(1);
}
console.log('Build outputs:');
for (const output of result.outputs) {
console.log(` ${output.path} (${output.size} bytes)`);
}
Performance Improvements
Benchmark Comparison
HTTP Server Performance (req/sec):
| Runtime | Hello World | JSON API | File Serving |
|---|---|---|---|
| Bun 1.2 | 250,000 | 180,000 | 150,000 |
| Bun 1.1 | 190,000 | 140,000 | 120,000 |
| Node.js 20 | 75,000 | 55,000 | 45,000 |
| Deno 1.40 | 95,000 | 70,000 | 60,000 |
Package Install Time (node_modules):
| Tool | Clean | With Cache |
|---|---|---|
| bun install | 2.1s | 0.3s |
| npm install | 15.2s | 8.5s |
| yarn install | 12.8s | 4.2s |
| pnpm install | 8.5s | 1.8s |
Optimized API Usage Example
// High-speed JSON server
import { serve } from 'bun';
const users = new Map<string, User>();
serve({
port: 3000,
async fetch(req) {
const url = new URL(req.url);
// Bun.router() - High-speed routing (future feature)
if (url.pathname.startsWith('/api/users')) {
const userId = url.pathname.split('/')[3];
if (req.method === 'GET') {
if (userId) {
const user = users.get(userId);
if (!user) {
return Response.json({ error: 'Not found' }, { status: 404 });
}
return Response.json(user);
}
return Response.json([...users.values()]);
}
if (req.method === 'POST') {
const body = await req.json();
const id = crypto.randomUUID();
const user = { id, ...body, createdAt: new Date().toISOString() };
users.set(id, user);
return Response.json(user, { status: 201 });
}
}
return new Response('Not Found', { status: 404 });
},
});
Bun Native Features
Bun.sql (High-Speed SQLite Operations)
// Bun.sql - Built-in SQLite driver
import { Database } from 'bun:sqlite';
const db = new Database(':memory:');
// Create table
db.run(`
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
// Prepared statements
const insertUser = db.prepare(`
INSERT INTO users (name, email) VALUES ($name, $email)
`);
const getUser = db.prepare(`
SELECT * FROM users WHERE id = $id
`);
const getAllUsers = db.prepare(`
SELECT * FROM users ORDER BY created_at DESC
`);
// Insert data
insertUser.run({ $name: 'Alice', $email: 'alice@example.com' });
insertUser.run({ $name: 'Bob', $email: 'bob@example.com' });
// Get data
const user = getUser.get({ $id: 1 });
console.log(user); // { id: 1, name: 'Alice', ... }
const users = getAllUsers.all();
console.log(users);
// Transaction
const insertMany = db.transaction((users: Array<{ name: string; email: string }>) => {
for (const user of users) {
insertUser.run({ $name: user.name, $email: user.email });
}
});
insertMany([
{ name: 'Charlie', email: 'charlie@example.com' },
{ name: 'Diana', email: 'diana@example.com' },
]);
Bun.password (Password Hashing)
// Bun.password - Secure password hashing
// Hash password
const hash = await Bun.password.hash('my-secure-password', {
algorithm: 'argon2id', // bcrypt, argon2id, argon2i, argon2d
memoryCost: 65536, // 64MB
timeCost: 3,
});
console.log(hash);
// $argon2id$v=19$m=65536,t=3,p=1$...
// Verify password
const isValid = await Bun.password.verify(
'my-secure-password',
hash
);
console.log(isValid); // true
// Using bcrypt
const bcryptHash = await Bun.password.hash('password123', {
algorithm: 'bcrypt',
cost: 12,
});
const bcryptValid = await Bun.password.verify('password123', bcryptHash);
Bun.sleep and Timers
// Bun.sleep - High-precision sleep
// Millisecond specification
await Bun.sleep(1000); // Wait 1 second
// Named timer (cancellable)
const timer = Bun.sleep(5000);
setTimeout(() => timer.cancel(), 2000); // Cancel after 2 seconds
try {
await timer;
} catch (e) {
console.log('Timer was cancelled');
}
// sleepSync (synchronous version)
Bun.sleepSync(100); // Synchronous wait 100ms
Migration Guide
Migrating from Node.js
// package.json
{
"scripts": {
// Node.js
"dev:node": "node --watch src/index.js",
"build:node": "tsc && node dist/index.js",
// Bun (direct TypeScript execution)
"dev": "bun --watch src/index.ts",
"build": "bun build src/index.ts --outdir=dist",
"start": "bun dist/index.js"
}
}
// Compatibility check
// bun pm untrusted - Check untrusted packages
// bun pm verify - Verify package integrity
// Common compatibility issues and solutions:
// 1. __dirname / __filename
// Node.js: Available globally
// Bun: Use import.meta in ESM
const __dirname = import.meta.dir;
const __filename = import.meta.file;
// 2. require() in ESM
// Bun uses import.meta.require()
const pkg = import.meta.require('./package.json');
// 3. Native addons
// Some native modules are incompatible
// Alternative: Bun native API or WASM
Express to Elysia Migration Example
// Express (Node.js)
import express from 'express';
const app = express();
app.get('/users/:id', (req, res) => {
const { id } = req.params;
res.json({ id, name: 'User' });
});
app.listen(3000);
// Elysia (Bun-optimized framework)
import { Elysia } from 'elysia';
const app = new Elysia()
.get('/users/:id', ({ params: { id } }) => ({
id,
name: 'User',
}))
.listen(3000);
console.log(`Server running at ${app.server?.hostname}:${app.server?.port}`);
Summary
Bun 1.2 has reached a practical level as a Node.js alternative.
Bun 1.2 Strengths
| Feature | Benefit |
|---|---|
| Ultra-fast startup | Faster development cycles |
| Direct TypeScript execution | No build step needed |
| All-in-one | Runtime + Bundler + PM |
| Node.js compatible | Reuse existing code |
Adoption Decision Criteria
- New projects: Can be actively adopted
- Existing Node.js projects: Migrate after compatibility testing
- Enterprise: Gradual introduction recommended
Bun is becoming the new standard for JavaScript/TypeScript development.