Bun 1.2: The JavaScript Runtime That Is Breaking Performance Records
Hello HaWkers, if you follow the JavaScript ecosystem, you've probably heard about Bun. This relatively new runtime is winning developers over with impressive performance numbers.
Have you ever been frustrated waiting for npm install to finish? Or maybe felt that your Node.js server could be faster? Bun promises to solve these problems and much more.
What Is Bun
Bun is an all-in-one JavaScript runtime and toolkit that includes:
Main Components:
- JavaScript runtime (Node.js alternative)
- Package manager (npm/yarn/pnpm alternative)
- Bundler (webpack/esbuild alternative)
- Test runner (Jest/Vitest alternative)
- Native TypeScript transpiler
The differentiator? All of this was written in Zig and C++ for maximum performance, using JavaScriptCore (Safari's engine) instead of V8.
Bun 1.2 News
Native Windows
Finally, full Windows support:
# Installation on Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"
# Or via npm
npm install -g bun
# Verify installation
bun --version
# 1.2.0Before version 1.2, Bun on Windows depended on WSL. Now it works natively.
Native S3 Object Storage
Bun 1.2 introduced native APIs for Amazon S3:
// Native S3 access - no heavy SDKs
import { S3Client } from "bun";
const s3 = new S3Client({
accessKeyId: Bun.env.AWS_ACCESS_KEY_ID,
secretAccessKey: Bun.env.AWS_SECRET_ACCESS_KEY,
region: "us-east-1"
});
// File upload
const file = Bun.file("./image.png");
await s3.write("my-bucket/image.png", file);
// Download
const downloaded = await s3.file("my-bucket/image.png");
await Bun.write("./downloaded.png", downloaded);
// Streaming large files
const stream = s3.file("my-bucket/large-video.mp4").stream();Native Postgres
PostgreSQL driver integrated into the runtime:
// Without installing pg or postgres.js
import { SQL } from "bun";
const sql = new SQL({
hostname: "localhost",
database: "myapp",
username: "user",
password: "password"
});
// Queries with tagged templates
const users = await sql`SELECT * FROM users WHERE active = true`;
// Parameterized queries (safe against SQL injection)
const userId = 123;
const user = await sql`SELECT * FROM users WHERE id = ${userId}`;
// Transactions
await sql.begin(async (tx) => {
await tx`UPDATE accounts SET balance = balance - 100 WHERE id = 1`;
await tx`UPDATE accounts SET balance = balance + 100 WHERE id = 2`;
});
Compared Performance
Package Manager
Let's compare dependency installation:
# Project with ~50 dependencies
# npm
time npm install
# real: 45.2s
# yarn
time yarn install
# real: 32.1s
# pnpm
time pnpm install
# real: 18.7s
# bun
time bun install
# real: 2.3sBun is consistently 10-20x faster than npm.
Runtime Performance
HTTP Server:
// Bun native server
Bun.serve({
port: 3000,
fetch(req) {
return new Response("Hello World");
}
});
// Results: ~185,000 req/sRequests per second comparison:
| Runtime | Hello World | JSON API | File Serve |
|---|---|---|---|
| Bun 1.2 | 185,000 | 142,000 | 78,000 |
| Deno 2.0 | 125,000 | 95,000 | 45,000 |
| Node 22 | 118,000 | 88,000 | 52,000 |
Bundler
# Build of large React project (~500 components)
# webpack
time npx webpack build
# real: 28.4s
# esbuild
time npx esbuild src/index.tsx --bundle --outdir=dist
# real: 0.8s
# bun
time bun build src/index.tsx --outdir=dist
# real: 0.4s
Using Bun in Practice
Creating a Project
# Create project
mkdir my-project && cd my-project
bun init
# Structure created:
# my-project/
# .gitignore
# bun.lockb
# index.ts
# package.json
# README.md
# tsconfig.jsonComplete Web Server
// server.ts
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";
const app = new Hono();
// Middlewares
app.use("*", logger());
app.use("/api/*", cors());
// Database connection (Bun native)
const db = new SQL({
hostname: Bun.env.DB_HOST,
database: Bun.env.DB_NAME,
username: Bun.env.DB_USER,
password: Bun.env.DB_PASSWORD
});
// Routes
app.get("/", (c) => c.text("Hello Bun!"));
app.get("/api/users", async (c) => {
const users = await db`SELECT id, name, email FROM users`;
return c.json(users);
});
app.post("/api/users", async (c) => {
const body = await c.req.json();
const { name, email } = body;
const [user] = await db`
INSERT INTO users (name, email)
VALUES (${name}, ${email})
RETURNING *
`;
return c.json(user, 201);
});
// File uploads (with native S3)
app.post("/api/upload", async (c) => {
const form = await c.req.formData();
const file = form.get("file") as File;
const s3 = new S3Client({
accessKeyId: Bun.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: Bun.env.AWS_SECRET_ACCESS_KEY!,
region: "us-east-1"
});
const key = `uploads/${Date.now()}-${file.name}`;
await s3.write(`my-bucket/${key}`, file);
return c.json({ url: `https://my-bucket.s3.amazonaws.com/${key}` });
});
export default {
port: 3000,
fetch: app.fetch
};Run and Develop
# Run in development (with hot reload)
bun --watch run server.ts
# Run in production
bun run server.ts
# package.json scripts
bun run dev
bun run build
bun run test
Test System
Bun has integrated test runner compatible with Jest:
// math.ts
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
export async function fetchUser(id: number) {
const response = await fetch(`https://api.example.com/users/${id}`);
return response.json();
}// math.test.ts
import { describe, test, expect, mock, beforeEach } from "bun:test";
import { add, multiply, fetchUser } from "./math";
describe("Math functions", () => {
test("add should sum two numbers", () => {
expect(add(2, 3)).toBe(5);
expect(add(-1, 1)).toBe(0);
});
test("multiply should multiply two numbers", () => {
expect(multiply(3, 4)).toBe(12);
expect(multiply(0, 100)).toBe(0);
});
});
describe("API functions", () => {
beforeEach(() => {
// Global fetch mock
global.fetch = mock(async (url: string) => {
return new Response(JSON.stringify({
id: 1,
name: "Test User"
}));
});
});
test("fetchUser should return user data", async () => {
const user = await fetchUser(1);
expect(user.name).toBe("Test User");
});
});# Run tests
bun test
# With coverage
bun test --coverage
# Watch mode
bun test --watch
# Filter tests
bun test --filter "Math"
Integrated Bundler
// bun.config.ts (optional)
export default {
entrypoints: ["./src/index.tsx"],
outdir: "./dist",
target: "browser",
minify: true,
sourcemap: "external",
splitting: true,
plugins: [
// Custom plugins
]
};# Simple build
bun build ./src/index.tsx --outdir ./dist
# Build with minification
bun build ./src/index.tsx --outdir ./dist --minify
# Build for Node.js
bun build ./src/server.ts --outdir ./dist --target node
# Watch mode
bun build ./src/index.tsx --outdir ./dist --watchBuild-Time Macros
A unique Bun feature is macros that run at compile time:
// config.ts
export const VERSION = await Bun.file("./version.txt").text();
export const BUILD_TIME = new Date().toISOString();
// This is evaluated at build time, not runtime!
export const ENV_CONFIG = {
apiUrl: Bun.env.API_URL,
debug: Bun.env.DEBUG === "true"
};// app.ts
import { VERSION, BUILD_TIME } from "./config" with { type: "macro" };
console.log(`Version: ${VERSION}`);
console.log(`Built at: ${BUILD_TIME}`);
// In the final bundle, these values are replaced by literal strings
Node.js Compatibility
Bun is highly compatible with Node.js:
// Most Node.js code works without changes
import express from "express";
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcrypt";
const app = express();
const prisma = new PrismaClient();
app.use(express.json());
app.post("/login", async (req, res) => {
const { email, password } = req.body;
const user = await prisma.user.findUnique({
where: { email }
});
if (!user) {
return res.status(401).json({ error: "User not found" });
}
const valid = await bcrypt.compare(password, user.password);
if (!valid) {
return res.status(401).json({ error: "Invalid password" });
}
res.json({ user: { id: user.id, email: user.email } });
});
// Works with bun run or node
app.listen(3000);Supported Node.js APIs
// Most Node.js APIs work
import fs from "fs";
import path from "path";
import crypto from "crypto";
import { Buffer } from "buffer";
import { EventEmitter } from "events";
import { Readable, Writable } from "stream";
// process global
console.log(process.env.NODE_ENV);
console.log(process.cwd());
// Additional Bun APIs
const file = Bun.file("./data.json");
const content = await file.text();
const hash = Bun.hash("sha256", "data");
When to Use Bun
Ideal Cases
1. New Projects That Need Performance:
// High performance APIs
// Real-time data processing
// WebSocket servers
// Microservices
Bun.serve({
port: 3000,
websocket: {
message(ws, message) {
// Broadcast to all clients
server.publish("chat", message);
}
},
fetch(req, server) {
if (server.upgrade(req)) {
return; // Upgrade to WebSocket
}
return new Response("Hello!");
}
});2. Scripts and CLI Tools:
#!/usr/bin/env bun
// Data migration script
import { SQL } from "bun";
const sourceDb = new SQL({ /* source config */ });
const targetDb = new SQL({ /* target config */ });
console.log("Starting migration...");
const users = await sourceDb`SELECT * FROM users`;
for (const user of users) {
await targetDb`
INSERT INTO users (id, name, email)
VALUES (${user.id}, ${user.name}, ${user.email})
`;
console.log(`Migrated user ${user.id}`);
}
console.log(`Migration complete! ${users.length} users migrated.`);3. When Build Time Matters:
# Faster CI/CD
# bun install + bun build in seconds
# vs npm install + webpack in minutesWhen to Avoid (For Now)
- Projects that depend on complex native addons
- Very Node.js-specific ecosystems
- When stability is more important than performance
- Teams that can't absorb learning curve
Migrating from Node.js
Step 1: Install Bun
# Unix/Mac
curl -fsSL https://bun.sh/install | bash
# Windows
powershell -c "irm bun.sh/install.ps1 | iex"Step 2: Convert package.json
# Remove node_modules and old lockfiles
rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml
# Install with Bun
bun install
# Creates bun.lockbStep 3: Test Compatibility
# Run tests
bun test
# Run application
bun run dev
# Verify everything worksStep 4: Optimize for Bun
// Replace packages with native APIs when possible
// Before: pg or postgres.js
import { Client } from "pg";
// After: Bun's native SQL
import { SQL } from "bun";
// Before: aws-sdk for S3
import AWS from "aws-sdk";
// After: Bun's native S3
import { S3Client } from "bun";
Conclusion
Bun 1.2 represents a significant advancement in the JavaScript ecosystem. With impressive performance, native APIs for common tasks, and excellent Node.js compatibility, it's becoming an increasingly viable option for serious projects.
The main recommendation is: experiment. Start with a new project or a script, and expand as you gain confidence. The Bun ecosystem is still maturing, but the direction is promising.
If you want to compare Bun with other runtime options, I recommend checking out another article: Deno 2.0 vs Node.js: The Battle of Runtimes where you'll discover how each runtime positions itself in the current market.

