bun

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Bun - The Fast JavaScript Runtime

Bun - 快速的JavaScript Runtime

Build and run JavaScript/TypeScript applications with Bun's all-in-one toolkit.
使用Bun的一体化工具包构建并运行JavaScript/TypeScript应用程序。

Quick Start

快速开始

bash
undefined
bash
undefined

Install Bun (macOS, Linux, WSL)

Install Bun (macOS, Linux, WSL)

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

Windows

Windows

powershell -c "irm bun.sh/install.ps1 | iex"
powershell -c "irm bun.sh/install.ps1 | iex"

Create new project

Create new project

bun init
bun init

Run TypeScript directly (no build step!)

Run TypeScript directly (no build step!)

bun run index.ts
bun run index.ts

Install packages (faster than npm)

Install packages (faster than npm)

bun install
bun install

Run scripts

Run scripts

bun run dev
undefined
bun run dev
undefined

Package Management

包管理

bash
undefined
bash
undefined

Install dependencies

Install dependencies

bun install # Install all from package.json bun add express # Add dependency bun add -d typescript # Add dev dependency bun add -g serve # Add global package
bun install # Install all from package.json bun add express # Add dependency bun add -d typescript # Add dev dependency bun add -g serve # Add global package

Remove packages

Remove packages

bun remove express
bun remove express

Update packages

Update packages

bun update
bun update

Run package binaries

Run package binaries

bunx prisma generate # Like npx but faster bunx create-next-app
bunx prisma generate # Like npx but faster bunx create-next-app

Lockfile

Lockfile

bun install --frozen-lockfile # CI mode
undefined
bun install --frozen-lockfile # CI mode
undefined

bun.lockb vs package-lock.json

bun.lockb 与 package-lock.json 对比

bash
undefined
bash
undefined

Bun uses binary lockfile (bun.lockb) - much faster

Bun uses binary lockfile (bun.lockb) - much faster

To generate yarn.lock for compatibility:

To generate yarn.lock for compatibility:

bun install --yarn
bun install --yarn

Import from other lockfiles

Import from other lockfiles

bun install # Auto-detects package-lock.json, yarn.lock
undefined
bun install # Auto-detects package-lock.json, yarn.lock
undefined

Bun Runtime

Bun运行时

Run Files

运行文件

bash
undefined
bash
undefined

Run any file

Run any file

bun run index.ts # TypeScript bun run index.js # JavaScript bun run index.jsx # JSX
bun run index.ts # TypeScript bun run index.js # JavaScript bun run index.jsx # JSX

Watch mode

Watch mode

bun --watch run index.ts
bun --watch run index.ts

Hot reload

Hot reload

bun --hot run server.ts
undefined
bun --hot run server.ts
undefined

Built-in APIs

内置API

typescript
// File I/O (super fast)
const file = Bun.file('data.json');
const content = await file.text();
const json = await file.json();
const bytes = await file.arrayBuffer();

// Write files
await Bun.write('output.txt', 'Hello, Bun!');
await Bun.write('data.json', JSON.stringify({ key: 'value' }));
await Bun.write('image.png', await fetch('https://example.com/img.png'));

// File metadata
const file = Bun.file('data.json');
console.log(file.size);       // bytes
console.log(file.type);       // MIME type
console.log(file.lastModified);

// Glob files
const glob = new Bun.Glob('**/*.ts');
for await (const file of glob.scan('.')) {
  console.log(file);
}
typescript
// File I/O (super fast)
const file = Bun.file('data.json');
const content = await file.text();
const json = await file.json();
const bytes = await file.arrayBuffer();

// Write files
await Bun.write('output.txt', 'Hello, Bun!');
await Bun.write('data.json', JSON.stringify({ key: 'value' }));
await Bun.write('image.png', await fetch('https://example.com/img.png'));

// File metadata
const file = Bun.file('data.json');
console.log(file.size);       // bytes
console.log(file.type);       // MIME type
console.log(file.lastModified);

// Glob files
const glob = new Bun.Glob('**/*.ts');
for await (const file of glob.scan('.')) {
  console.log(file);
}

HTTP Server

HTTP服务器

typescript
// Simple server
const server = Bun.serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);
    
    if (url.pathname === '/') {
      return new Response('Hello, Bun!');
    }
    
    if (url.pathname === '/json') {
      return Response.json({ message: 'Hello!' });
    }
    
    return new Response('Not Found', { status: 404 });
  },
});

console.log(`Server running at http://localhost:${server.port}`);
typescript
// Simple server
const server = Bun.serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);
    
    if (url.pathname === '/') {
      return new Response('Hello, Bun!');
    }
    
    if (url.pathname === '/json') {
      return Response.json({ message: 'Hello!' });
    }
    
    return new Response('Not Found', { status: 404 });
  },
});

console.log(`Server running at http://localhost:${server.port}`);

Advanced Server

高级服务器

typescript
Bun.serve({
  port: 3000,
  
  // Main request handler
  async fetch(req, server) {
    const url = new URL(req.url);
    
    // WebSocket upgrade
    if (url.pathname === '/ws') {
      const upgraded = server.upgrade(req, {
        data: { userId: '123' },  // Attach data to socket
      });
      if (upgraded) return undefined;
    }
    
    // Static files
    if (url.pathname.startsWith('/static/')) {
      const filePath = `./public${url.pathname}`;
      const file = Bun.file(filePath);
      if (await file.exists()) {
        return new Response(file);
      }
    }
    
    // JSON API
    if (url.pathname === '/api/data' && req.method === 'POST') {
      const body = await req.json();
      return Response.json({ received: body });
    }
    
    return new Response('Not Found', { status: 404 });
  },
  
  // WebSocket handlers
  websocket: {
    open(ws) {
      console.log('Client connected:', ws.data.userId);
      ws.subscribe('chat');  // Pub/sub
    },
    message(ws, message) {
      // Broadcast to all subscribers
      ws.publish('chat', message);
    },
    close(ws) {
      console.log('Client disconnected');
    },
  },
  
  // Error handling
  error(error) {
    return new Response(`Error: ${error.message}`, { status: 500 });
  },
});
typescript
Bun.serve({
  port: 3000,
  
  // Main request handler
  async fetch(req, server) {
    const url = new URL(req.url);
    
    // WebSocket upgrade
    if (url.pathname === '/ws') {
      const upgraded = server.upgrade(req, {
        data: { userId: '123' },  // Attach data to socket
      });
      if (upgraded) return undefined;
    }
    
    // Static files
    if (url.pathname.startsWith('/static/')) {
      const filePath = `./public${url.pathname}`;
      const file = Bun.file(filePath);
      if (await file.exists()) {
        return new Response(file);
      }
    }
    
    // JSON API
    if (url.pathname === '/api/data' && req.method === 'POST') {
      const body = await req.json();
      return Response.json({ received: body });
    }
    
    return new Response('Not Found', { status: 404 });
  },
  
  // WebSocket handlers
  websocket: {
    open(ws) {
      console.log('Client connected:', ws.data.userId);
      ws.subscribe('chat');  // Pub/sub
    },
    message(ws, message) {
      // Broadcast to all subscribers
      ws.publish('chat', message);
    },
    close(ws) {
      console.log('Client disconnected');
    },
  },
  
  // Error handling
  error(error) {
    return new Response(`Error: ${error.message}`, { status: 500 });
  },
});

WebSocket Client

WebSocket客户端

typescript
const ws = new WebSocket('ws://localhost:3000/ws');

ws.onopen = () => {
  ws.send('Hello, server!');
};

ws.onmessage = (event) => {
  console.log('Received:', event.data);
};
typescript
const ws = new WebSocket('ws://localhost:3000/ws');

ws.onopen = () => {
  ws.send('Hello, server!');
};

ws.onmessage = (event) => {
  console.log('Received:', event.data);
};

Bun APIs

Bun API

SQLite (Built-in)

SQLite(内置)

typescript
import { Database } from 'bun:sqlite';

const db = new Database('mydb.sqlite');

// Create table
db.run(`
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE
  )
`);

// Insert
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
insert.run('Alice', 'alice@example.com');

// Query
const query = db.prepare('SELECT * FROM users WHERE id = ?');
const user = query.get(1);

// All results
const allUsers = db.prepare('SELECT * FROM users').all();

// Transaction
const insertMany = db.transaction((users) => {
  for (const user of users) {
    insert.run(user.name, user.email);
  }
});

insertMany([
  { name: 'Bob', email: 'bob@example.com' },
  { name: 'Charlie', email: 'charlie@example.com' },
]);
typescript
import { Database } from 'bun:sqlite';

const db = new Database('mydb.sqlite');

// Create table
db.run(`
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE
  )
`);

// Insert
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
insert.run('Alice', 'alice@example.com');

// Query
const query = db.prepare('SELECT * FROM users WHERE id = ?');
const user = query.get(1);

// All results
const allUsers = db.prepare('SELECT * FROM users').all();

// Transaction
const insertMany = db.transaction((users) => {
  for (const user of users) {
    insert.run(user.name, user.email);
  }
});

insertMany([
  { name: 'Bob', email: 'bob@example.com' },
  { name: 'Charlie', email: 'charlie@example.com' },
]);

Password Hashing (Built-in)

密码哈希(内置)

typescript
// Hash password
const hash = await Bun.password.hash('mypassword', {
  algorithm: 'argon2id',  // or 'bcrypt'
  memoryCost: 65536,      // 64 MB
  timeCost: 2,
});

// Verify password
const isValid = await Bun.password.verify('mypassword', hash);
typescript
// Hash password
const hash = await Bun.password.hash('mypassword', {
  algorithm: 'argon2id',  // or 'bcrypt'
  memoryCost: 65536,      // 64 MB
  timeCost: 2,
});

// Verify password
const isValid = await Bun.password.verify('mypassword', hash);

Spawn Processes

生成进程

typescript
// Spawn process
const proc = Bun.spawn(['ls', '-la'], {
  cwd: '/home/user',
  env: { ...process.env, MY_VAR: 'value' },
  stdout: 'pipe',
});

const output = await new Response(proc.stdout).text();
console.log(output);

// Spawn sync
const result = Bun.spawnSync(['echo', 'hello']);
console.log(result.stdout.toString());

// Shell command
const { stdout } = Bun.spawn({
  cmd: ['sh', '-c', 'echo $HOME'],
  stdout: 'pipe',
});
typescript
// Spawn process
const proc = Bun.spawn(['ls', '-la'], {
  cwd: '/home/user',
  env: { ...process.env, MY_VAR: 'value' },
  stdout: 'pipe',
});

const output = await new Response(proc.stdout).text();
console.log(output);

// Spawn sync
const result = Bun.spawnSync(['echo', 'hello']);
console.log(result.stdout.toString());

// Shell command
const { stdout } = Bun.spawn({
  cmd: ['sh', '-c', 'echo $HOME'],
  stdout: 'pipe',
});

Hashing & Crypto

哈希与加密

typescript
// Hash strings
const hash = Bun.hash('hello world');  // Wyhash (fast)

// Crypto hashes
const sha256 = new Bun.CryptoHasher('sha256');
sha256.update('data');
const digest = sha256.digest('hex');

// One-liner
const md5 = Bun.CryptoHasher.hash('md5', 'data', 'hex');

// HMAC
const hmac = Bun.CryptoHasher.hmac('sha256', 'secret-key', 'data', 'hex');
typescript
// Hash strings
const hash = Bun.hash('hello world');  // Wyhash (fast)

// Crypto hashes
const sha256 = new Bun.CryptoHasher('sha256');
sha256.update('data');
const digest = sha256.digest('hex');

// One-liner
const md5 = Bun.CryptoHasher.hash('md5', 'data', 'hex');

// HMAC
const hmac = Bun.CryptoHasher.hmac('sha256', 'secret-key', 'data', 'hex');

Bundler

打包工具

bash
undefined
bash
undefined

Bundle for browser

Bundle for browser

bun build ./src/index.ts --outdir ./dist
bun build ./src/index.ts --outdir ./dist

Bundle options

Bundle options

bun build ./src/index.ts
--outdir ./dist
--minify
--sourcemap
--target browser
--splitting
--entry-naming '[dir]/[name]-[hash].[ext]'
undefined
bun build ./src/index.ts
--outdir ./dist
--minify
--sourcemap
--target browser
--splitting
--entry-naming '[dir]/[name]-[hash].[ext]'
undefined

Build API

构建API

typescript
const result = await Bun.build({
  entrypoints: ['./src/index.ts'],
  outdir: './dist',
  minify: true,
  sourcemap: 'external',
  target: 'browser',  // 'bun' | 'node' | 'browser'
  splitting: true,
  naming: {
    entry: '[dir]/[name]-[hash].[ext]',
    chunk: '[name]-[hash].[ext]',
    asset: '[name]-[hash].[ext]',
  },
  external: ['react', 'react-dom'],
  define: {
    'process.env.NODE_ENV': JSON.stringify('production'),
  },
  loader: {
    '.png': 'file',
    '.svg': 'text',
  },
});

if (!result.success) {
  console.error('Build failed:', result.logs);
}
typescript
const result = await Bun.build({
  entrypoints: ['./src/index.ts'],
  outdir: './dist',
  minify: true,
  sourcemap: 'external',
  target: 'browser',  // 'bun' | 'node' | 'browser'
  splitting: true,
  naming: {
    entry: '[dir]/[name]-[hash].[ext]',
    chunk: '[name]-[hash].[ext]',
    asset: '[name]-[hash].[ext]',
  },
  external: ['react', 'react-dom'],
  define: {
    'process.env.NODE_ENV': JSON.stringify('production'),
  },
  loader: {
    '.png': 'file',
    '.svg': 'text',
  },
});

if (!result.success) {
  console.error('Build failed:', result.logs);
}

Testing

测试

typescript
// test.ts
import { describe, test, expect, beforeAll, afterAll, mock } from 'bun:test';

describe('Math operations', () => {
  test('addition', () => {
    expect(1 + 1).toBe(2);
  });
  
  test('array contains', () => {
    expect([1, 2, 3]).toContain(2);
  });
  
  test('object matching', () => {
    expect({ name: 'Alice', age: 30 }).toMatchObject({ name: 'Alice' });
  });
  
  test('async test', async () => {
    const result = await Promise.resolve(42);
    expect(result).toBe(42);
  });
  
  test('throws error', () => {
    expect(() => {
      throw new Error('fail');
    }).toThrow('fail');
  });
});

// Mocking
const mockFn = mock(() => 'mocked');
mockFn();
expect(mockFn).toHaveBeenCalled();

// Mock modules
mock.module('./database', () => ({
  query: mock(() => [{ id: 1 }]),
}));
bash
undefined
typescript
// test.ts
import { describe, test, expect, beforeAll, afterAll, mock } from 'bun:test';

describe('Math operations', () => {
  test('addition', () => {
    expect(1 + 1).toBe(2);
  });
  
  test('array contains', () => {
    expect([1, 2, 3]).toContain(2);
  });
  
  test('object matching', () => {
    expect({ name: 'Alice', age: 30 }).toMatchObject({ name: 'Alice' });
  });
  
  test('async test', async () => {
    const result = await Promise.resolve(42);
    expect(result).toBe(42);
  });
  
  test('throws error', () => {
    expect(() => {
      throw new Error('fail');
    }).toThrow('fail');
  });
});

// Mocking
const mockFn = mock(() => 'mocked');
mockFn();
expect(mockFn).toHaveBeenCalled();

// Mock modules
mock.module('./database', () => ({
  query: mock(() => [{ id: 1 }]),
}));
bash
undefined

Run tests

Run tests

bun test
bun test

Watch mode

Watch mode

bun test --watch
bun test --watch

Specific file

Specific file

bun test user.test.ts
bun test user.test.ts

Coverage

Coverage

bun test --coverage
undefined
bun test --coverage
undefined

Node.js Compatibility

Node.js兼容性

typescript
// Most Node.js APIs work out of the box
import fs from 'fs';
import path from 'path';
import { createServer } from 'http';
import express from 'express';

// Bun implements Node.js APIs
const data = fs.readFileSync('file.txt', 'utf-8');
const fullPath = path.join(__dirname, 'file.txt');

// Express works!
const app = express();
app.get('/', (req, res) => res.send('Hello!'));
app.listen(3000);
typescript
// Most Node.js APIs work out of the box
import fs from 'fs';
import path from 'path';
import { createServer } from 'http';
import express from 'express';

// Bun implements Node.js APIs
const data = fs.readFileSync('file.txt', 'utf-8');
const fullPath = path.join(__dirname, 'file.txt');

// Express works!
const app = express();
app.get('/', (req, res) => res.send('Hello!'));
app.listen(3000);

Node.js vs Bun APIs

Node.js 与 Bun API 对比

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

// Bun way (faster)
const content = await Bun.file('file.txt').text();

// Node.js crypto
import crypto from 'crypto';
const hash = crypto.createHash('sha256').update('data').digest('hex');

// Bun way (faster)
const hash = Bun.CryptoHasher.hash('sha256', 'data', 'hex');
typescript
// Node.js way
import { readFile } from 'fs/promises';
const content = await readFile('file.txt', 'utf-8');

// Bun way (faster)
const content = await Bun.file('file.txt').text();

// Node.js crypto
import crypto from 'crypto';
const hash = crypto.createHash('sha256').update('data').digest('hex');

// Bun way (faster)
const hash = Bun.CryptoHasher.hash('sha256', 'data', 'hex');

Environment Variables

环境变量

typescript
// .env file support (built-in, no dotenv needed!)
// .env
// DATABASE_URL=postgres://localhost/db
// API_KEY=secret

// Access env vars
const dbUrl = Bun.env.DATABASE_URL;
const apiKey = process.env.API_KEY;  // Also works

// bunfig.toml for Bun config
// [run]
// preload = ["./setup.ts"]
typescript
// .env file support (built-in, no dotenv needed!)
// .env
// DATABASE_URL=postgres://localhost/db
// API_KEY=secret

// Access env vars
const dbUrl = Bun.env.DATABASE_URL;
const apiKey = process.env.API_KEY;  // Also works

// bunfig.toml for Bun config
// [run]
// preload = ["./setup.ts"]

HTTP Client

HTTP客户端

typescript
// Fetch (optimized in Bun)
const response = await fetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token',
  },
  body: JSON.stringify({ key: 'value' }),
});

const data = await response.json();

// Streaming response
const response = await fetch('https://api.example.com/stream');
const reader = response.body?.getReader();

while (true) {
  const { done, value } = await reader!.read();
  if (done) break;
  console.log(new TextDecoder().decode(value));
}
typescript
// Fetch (optimized in Bun)
const response = await fetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token',
  },
  body: JSON.stringify({ key: 'value' }),
});

const data = await response.json();

// Streaming response
const response = await fetch('https://api.example.com/stream');
const reader = response.body?.getReader();

while (true) {
  const { done, value } = await reader!.read();
  if (done) break;
  console.log(new TextDecoder().decode(value));
}

Project Structure

项目结构

my-bun-project/
├── src/
│   ├── index.ts          # Entry point
│   ├── routes/
│   │   └── api.ts
│   └── lib/
│       └── database.ts
├── tests/
│   └── index.test.ts
├── public/
│   └── static files
├── package.json
├── bunfig.toml           # Bun config (optional)
├── tsconfig.json
└── .env
my-bun-project/
├── src/
│   ├── index.ts          # Entry point
│   ├── routes/
│   │   └── api.ts
│   └── lib/
│       └── database.ts
├── tests/
│   └── index.test.ts
├── public/
│   └── static files
├── package.json
├── bunfig.toml           # Bun config (optional)
├── tsconfig.json
└── .env

bunfig.toml

bunfig.toml

toml
[install]
toml
[install]

Use exact versions by default

Use exact versions by default

exact = true
exact = true

Registry

Registry

[run]
[run]

Scripts to run before
bun run

Scripts to run before
bun run

preload = ["./instrumentation.ts"]
[test]
preload = ["./instrumentation.ts"]
[test]

Test configuration

Test configuration

coverage = true coverageDir = "coverage"
[bundle]
coverage = true coverageDir = "coverage"
[bundle]

Default bundle config

Default bundle config

minify = true sourcemap = "external"
undefined
minify = true sourcemap = "external"
undefined

Performance Comparison

性能对比

OperationNode.jsBunSpeedup
Start time~40ms~7ms5.7x
Package install~10s~1s10x
File readbaselinefaster10x
HTTP serverbaselinefaster4x
SQLiteexternalbuilt-in3x
TypeScriptcompile needednative
操作Node.jsBun提速倍数
启动时间~40ms~7ms5.7倍
包安装~10s~1s10倍
文件读取基准值更快10倍
HTTP服务器基准值更快4倍
SQLite需外部依赖内置3倍
TypeScript需要编译原生支持无编译步骤

Resources

资源