首页 / Bun 入门教程 / Bun.* API 概览

Bun 入门教程

Bun.* API 概览

本教程共 34 篇 · 第 9 篇 · 更新于 2026-08-06

BunBun.serveBun.fileBun.spawnBun.$内置 APIbun:sqlite

本节目标:

  • 理解 Bun 内置 API 的设计取向:能用 Web 标准就用 Web 标准,只在服务端无标准处新增 Bun.*
  • 建立一张”心智地图”,知道 HTTP 服务、文件、子进程、哈希、数据库等能力分别落在哪个 API 上。
  • 通过最小片段上手最常用的几个:Bun.serveBun.fileBun.writeBun.spawnBun.$
  • 区分 Bun 全局对象和 bun: 前缀内置模块两类入口。
  • 知道怎样拿到完整的 TypeScript 类型提示,以及这些 API 和 node: 模块如何共存。

9.1 设计取向:先标准,后自研

Bun 在 Bun 全局对象和若干内置模块上实现了一整套原生 API。它们是经过重度优化的、“Bun 风格”的标准做法。但在动手记 API 之前,先理解它的取舍逻辑,会让后面的学习省很多力气:

Bun 尽一切可能实现 Web 标准 API。 fetchRequestResponseHeadersURLBlobReadableStreamTextEncodercryptoWebSocketAbortController——这些在浏览器里怎么用,在 Bun 里就怎么用。

只有在服务端任务缺少标准的地方,Bun 才引入新 API。 典型的就是文件 I/O 和启动 HTTP 服务器——Web 平台从来没有为它们定义过标准。即便是这些自研 API,Bun 也依然建立在 BlobURLRequest 这些标准原语之上。

看一眼最经典的例子就明白了:

// server.ts
Bun.serve({
  fetch(req: Request) {
    return new Response("Success!");
  },
});

Bun.serve 是 Bun 自己的 API,但它的入参是标准 Request、返回值是标准 Response。你写的处理函数几乎可以原样搬到 Cloudflare Workers 或 Deno 上。这就是 Bun 内置 API 的一贯风格:外壳是 Bun 的,内核是标准的。

这条取向带来一个直接的学习收益:你不需要背一整套私有对象模型,只需要记住”入口在哪里”,剩下的都是你已经熟悉的 Web API。

9.2 两类入口

Bun 的内置能力通过两种方式暴露:

第一类:Bun 全局对象。 不需要 import,直接用:

Bun.version;      // 当前 bun CLI 的版本号字符串
Bun.file("a.txt");
Bun.serve({ /* ... */ });

第二类:bun: 前缀的内置模块。 需要显式导入:

import { Database } from "bun:sqlite";
import { test, expect } from "bun:test";
import { dlopen } from "bun:ffi";

bun: 前缀是 Bun 内置模块的命名空间,和 Node.js 的 node: 前缀是同一个思路——明确标识”这是运行时自带的,不是 npm 包”。这个前缀的解析规则会在下一章展开。

还有少数 API 是”两栖”的,比如 Bun Shell 既可以从 bun 包导入,也挂在全局对象上:

import { $ } from "bun";
// 等价于 Bun.$

9.3 分类速查表

下面这张表按主题列出 Bun.* 与内置模块的主要 API,作为你后续查阅的索引。不必现在全部记住,知道”有这么个东西”就够了。

主题API
HTTP 服务Bun.serve
ShellBun.$(也可 import { $ } from "bun"
打包器Bun.build
文件 I/OBun.fileBun.writeBun.stdinBun.stdoutBun.stderr
子进程Bun.spawnBun.spawnSync
TCP 套接字Bun.listenBun.connect
UDP 套接字Bun.udpSocket
WebSocketnew WebSocket()(客户端)、Bun.serve(服务端)
转译器Bun.Transpiler
文件系统路由Bun.FileSystemRouter
流式 HTML 处理HTMLRewriter
哈希与密码Bun.passwordBun.hashBun.CryptoHasherBun.sha
CSRF 防护Bun.CSRF.generateBun.CSRF.verify
SQLitebun:sqlite
SQL 客户端Bun.SQLBun.sql
Redis(Valkey)客户端Bun.RedisClientBun.redis
FFI(外部函数接口)bun:ffi
DNSBun.dns.lookupBun.dns.prefetchBun.dns.getCacheStats
测试bun:test
Worker 线程new Worker()
模块加载器插件Bun.plugin
Glob 匹配Bun.Glob
CookieBun.CookieBun.CookieMap
Node-APINode-API 原生插件支持
模块元信息import.meta
运行时信息Bun.versionBun.revisionBun.envBun.main
休眠与计时Bun.sleep()Bun.sleepSync()Bun.nanoseconds()
随机与 UUIDBun.randomUUIDv7()
系统环境Bun.which()
比较与检视Bun.peek()Bun.deepEquals()Bun.deepMatchBun.inspect()
字符串处理Bun.escapeHTML()Bun.stringWidth()Bun.indexOfLine
URL 与路径Bun.fileURLToPath()Bun.pathToFileURL()
压缩Bun.gzipSync()Bun.gunzipSync()Bun.deflateSync()Bun.inflateSync()Bun.zstdCompressSync()Bun.zstdDecompressSync()
流处理工具Bun.readableStreamToText()Bun.readableStreamToBytes()Bun.readableStreamToJSON()
内存与缓冲区Bun.ArrayBufferSinkBun.allocUnsafeBun.concatArrayBuffers
模块解析Bun.resolveSync()
解析与格式化Bun.semverBun.TOML.parseBun.markdownBun.colorBun.Image
底层/内部Bun.mmapBun.gcBun.generateHeapSnapshotbun:jsc
Tip

这张表最实用的读法不是”从头背到尾”,而是遇到需求时反查:想跑个子进程 → 看到 Bun.spawn;想算个密码哈希 → 看到 Bun.password;想读环境变量 → 看到 Bun.env

9.4 高频 API 最小片段

下面挑五个最常用的,各给一段可直接运行的最小代码。它们各自的完整用法会在第六篇「内置 API 精选」里展开。

Bun.serve —— 启动 HTTP 服务

// server.ts
const server = Bun.serve({
  port: 3000,
  routes: {
    // 静态响应
    "/api/status": new Response("OK"),

    // 动态路由参数
    "/users/:id": req => new Response(`Hello User ${req.params.id}!`),

    // 按 HTTP 方法分发
    "/api/posts": {
      GET: () => new Response("List posts"),
      POST: async req => {
        const body = await req.json();
        return Response.json({ created: true, ...body });
      },
    },
  },

  // 未匹配路由的兜底
  fetch(req) {
    return new Response("Not Found", { status: 404 });
  },
});

console.log(`Server running at ${server.url}`);

运行:

bun run server.ts
Note

routes 选项需要 Bun v1.2.3 及以上;在更老的版本上必须提供 fetch 处理函数。当前基线 v1.3.14 两者都支持,fetch 作为兜底仍然很有用。
端口的默认值依次取自 $BUN_PORT$PORT$NODE_PORT,都没有时为 3000;把 port 设为 0 可随机选取一个可用端口,随后从 server.portserver.url 读回。

Bun.file —— 惰性读取文件

Bun.file(path) 返回一个 BunFile,它不会立刻读盘,只是创建了一个引用:

const foo = Bun.file("foo.txt"); // 相对于当前工作目录
foo.size; // 字节数
foo.type; // MIME 类型

BunFile 遵循 Blob 接口,所以可以用你熟悉的方式取内容:

const foo = Bun.file("foo.txt");

await foo.text();        // 字符串
await foo.json();        // 解析为 JSON 对象
foo.stream();            // ReadableStream
await foo.arrayBuffer(); // ArrayBuffer
await foo.bytes();       // Uint8Array

文件不存在也可以创建引用,用 .exists() 判断:

const notreal = Bun.file("notreal.txt");
notreal.size;                  // 0
const exists = await notreal.exists(); // false

标准输入输出同样以 BunFile 的形式暴露:

Bun.stdin;  // 只读
Bun.stdout;
Bun.stderr;

Bun.write —— 万能写入

Bun.write(destination, data) 返回写入的字节数。它对”目标”和”数据”都很宽容——字符串、BlobBunFileResponse、TypedArray 都能作为数据源:

await Bun.write("output.txt", "Hello Bun!");

// 直接把一个 Response 的响应体落盘
await Bun.write("bun.html", await fetch("https://bun.com"));

// 文件复制:源和目标都是 BunFile
await Bun.write(Bun.file("copy.txt"), Bun.file("output.txt"));
Tip

Bun.file / Bun.write 覆盖的是”读写单个文件”这件事。像 mkdirreaddirstat 这类目录操作,直接用 node:fs 即可——Bun 对 node:fs 的实现相当完整,两者可以自由混用。

Bun.spawn —— 启动子进程

命令以字符串数组形式传入,返回一个 Bun.Subprocess

const proc = Bun.spawn(["bun", "--version"]);
console.log(await proc.exited); // 退出码,0 表示成功

第二个参数用于配置子进程:

const proc = Bun.spawn(["bun", "--version"], {
  cwd: "./path/to/subdir",              // 工作目录
  env: { ...process.env, FOO: "bar" },  // 环境变量
  onExit(proc, exitCode, signalCode, error) {
    // 退出回调
  },
});

proc.pid; // 子进程 PID

读取子进程输出:

const proc = Bun.spawn(["echo", "hello"]);
const text = await proc.stdout.text();
console.log(text); // "hello\n"

需要阻塞式调用时用 Bun.spawnSync(第 8 章嵌入 Git 哈希的宏就用了它)。

Bun.$ —— Bun Shell

Bun Shell 是一个跨平台的类 bash shell,用模板字符串直接写命令:

import { $ } from "bun";

await $`echo "Hello World!"`; // 输出 Hello World!

它的几个关键特性值得单独记住:

  • 跨平台:Windows / Linux / macOS 行为一致,lscdrm 等常用命令由 Bun 原生实现,不再需要 rimrafcross-env 这类兼容包。
  • 默认转义:所有插值字符串默认被转义,从机制上避免 shell 注入。
  • JavaScript 互操作ResponseBlobArrayBufferBun.file(path) 都能当作 stdin / stdout 使用。
import { $ } from "bun";

const response = await fetch("https://example.com");

// 把 Response 直接当作 stdin
await $`cat < ${response} | wc -c`;

静默执行与取文本输出:

import { $ } from "bun";

await $`echo "Hello World!"`.quiet();      // 不打印
const out = await $`echo "Hello"`.text();  // 取字符串,text() 会自动 quiet

Bun.Glob —— 文件匹配

import { Glob } from "bun";

const glob = new Glob("**/*.ts");

// 递归扫描当前目录
for await (const file of glob.scan(".")) {
  console.log(file);
}

// 也可以只做字符串匹配
new Glob("*.ts").match("index.ts"); // true

9.5 类型提示

要在编辑器里获得完整的 Bun.* 类型补全,安装官方类型包:

bun add -d @types/bun

然后在 tsconfig.json 里确保它被识别(bun init 生成的配置已经处理好了)。装好之后,Bun.serve 的选项、BunFile 的方法签名、Subprocess 的字段都会有完整提示。

Note

Bun 全局对象的 API 表面仍在持续扩充,官方文档也明确标注它”会随新 API 加入而变化”。锁定 @types/bun 的版本与你使用的 Bun 版本一致,可以避免类型和实际行为对不上。

9.6 和 Node.js API 的关系

这一点常被初学者误解,需要说清楚:Bun.* 不是用来替换 node: 模块的,两者是共存关系。

Bun 的目标是 100% Node.js API 兼容(这是目标,尚未完全达成),因此绝大多数 node: 内置模块在 Bun 里可以直接用:

import { readdir, mkdir } from "node:fs/promises";
import path from "node:path";
import { createServer } from "node:http";

同时,Bun 也实现了大量 Node.js 全局变量:Bufferprocess__dirname__filenamerequireglobal 等等。

那什么时候该用 Bun.*?给一个实用判断:

  • 需要跨运行时可移植 → 用 Web 标准 API 或 node: 模块。
  • 明确只跑在 Bun 上、且该操作是性能热点 → 优先用 Bun.*,它们针对 Bun 做过重度优化。
  • Bun.* 没覆盖到的能力(如目录遍历、路径拼接) → 直接用 node: 模块,不必绕路。

不需要在两者之间”二选一”。一个真实项目里同时出现 Bun.filenode:path 是完全正常的写法。

9.7 小结

本章建立的是一张地图,不是一本词典。需要带走的几条:

  1. 设计取向:Web 标准优先,Bun.* 只补服务端空白,且建立在标准原语之上。
  2. 两类入口Bun 全局对象(免导入)与 bun: 前缀内置模块(需导入)。
  3. 五个高频 APIBun.serve(HTTP)、Bun.file(读)、Bun.write(写)、Bun.spawn(子进程)、Bun.$(Shell)。
  4. 类型提示@types/bun,版本与 Bun 对齐。
  5. 和 Node.js 共存,不是互斥替代。

下一章我们进入模块解析——搞清楚 import "./hello"import "react"import "bun:sqlite"import "node:fs" 这四种写法,Bun 分别是怎么找到对应文件的。