Bun 1.3 深度拆解:当全栈工具包决定让 Claude 把自己从 Zig 重写进 Rust——从 JavaScriptCore 内核、统一数据库 API 到 AI 驱动百万行重写的新范式
如果一个 JavaScript 运行时,既能当 Node 用、又能当 Webpack 用、还能当 Jest 用、甚至把 PostgreSQL 客户端和 S3 SDK 都内置了,你会不会觉得它"管得太宽"?
2026 年的 Bun 就是这样一位"什么都想干"的选手。更离谱的是:它的创始人 Jarred Sumner 在 5 月 11 日发了一条推文,宣布要用 Claude Code 把整个运行时从 Zig 重写进 Rust,六天改写近百万行代码;与此同时,Bun 宣布加入 Anthropic。
这篇文章,我们把它扒个底朝天。
一、背景:JavaScript 运行时的三次浪潮
要理解 Bun 为什么存在,得先看懂 JavaScript 运行时这三十年来的三次"范式革命"。
第一次浪潮:Node.js(2009)。Ryan Dahl 用 V8 + libuv 把 JavaScript 带到了服务端,用事件循环和"非阻塞 IO"重新定义了后端。这是一次"能不能跑"的革命。但它留下了两个历史包袱:
- CommonJS 模块系统——当年为了快,设计得相当随意,导致今天的 ESM / CJS 互操作仍是一团浆糊;
- npm 的"依赖地狱"——
node_modules体积爆炸、锁文件玄学、安装动辄几十秒。
第二次浪潮:Deno(2018)。还是 Ryan Dahl,带着"我后悔了"的反思卷土重来:默认安全沙箱、原生支持 TypeScript、URL import、内置工具链。这是一次"能不能更安全、更现代"的革命。但 Deno 的 URL import 和过于理想化的设计,让它在工程落地上始终不温不火。
第三次浪潮:Bun(2022)。前 Stripe 工程师 Jarred Sumner 换了个角度思考——与其重新设计语言生态,不如把开发者每天要用的所有工具都重新造一遍,并且让它快得离谱。Bun 的口号从一开始就不是"更好的 Node",而是 "All-in-One Toolkit":一个二进制文件,同时是 runtime、bundler、transpiler、package manager、test runner、task runner。
到 2026 年 8 月,Bun 已经迭代到 v1.3.14。这一年的两个新闻直接把 Bun 推上了风口:
- Bun 加入 Anthropic:官方站点头条直接挂着 "Bun is joining Anthropic",Anthropic 押注 Bun 作为 AI 原生时代的 JS/TS 工具链底座。
- Zig → Rust 重写:创始人宣布用 AI 把底层从 Zig 迁到 Rust,近百万行代码、六天完成,通过了 99.8% 的既有测试套件。
这两个事件叠加在一起,让 Bun 的故事从"又一个快一点的运行时",变成了一个关于工程可靠性、AI 辅助重写、以及工具链整合边界的深层样本。下面我们一层层拆。
二、核心概念:到底什么是 "All-in-One Toolkit"
很多初学者对 Bun 的误解是"哦,又一个 Node 替代品"。错。Bun 的野心是把下面这些东西全部塞进一个二进制:
| 能力 | Bun 提供 | 传统 Node 生态要装什么 |
|---|---|---|
| 运行时 | bun run | node |
| 包管理 | bun install | npm / pnpm / yarn |
| 打包器 | bun build | webpack / rollup / esbuild |
| 转译器 | 内置(TS/JSX/CSS) | babel / tsc / swc |
| 测试 | bun test | jest / vitest |
| 任务运行 | bun run <script> | npm scripts |
| SQLite 客户端 | bun:sqlite | better-sqlite3 |
| SQL 客户端 | bun:sql(PG/MySQL/SQLite) | pg / mysql2 |
| 对象存储 | Bun.s3 | aws-sdk / @aws-sdk/client-s3 |
| 密钥管理 | Bun.secrets | dotenv + Vault |
| FFI | bun:ffi | ffi-napi / node-ffi |
注意一个关键点:Bun 不是把 npm 包拼起来,而是用 Zig(现在是 Rust)从底层重新实现这些能力。这意味着它的 SQLite 驱动不是对 better-sqlite3 的封装,而是直接用原生代码绑定;它的 HTTP 服务不是基于 Node 的 http 模块,而是自建的事件循环。
2.1 引擎之争:为什么是 JavaScriptCore 而不是 V8
Bun 选择 JavaScriptCore(JSC,Safari 的引擎) 而非 Node 用的 V8。这是个反直觉但经过计算的决定:
- 冷启动更快:JSC 的字节码缓存和启动路径比 V8 轻,对 CLI、Serverless、短生命周期进程尤其友好;
- 内存占用更低:同样的 "Hello World" 服务,JSC 常驻内存往往显著低于 V8;
- 更易嵌入:JSC 的 C API 比 V8 的嵌入接口友好,这让用 Zig/Rust "手搓" 绑定变得可行。
代价是:V8 在长时间运行、重计算场景(比如大型 SSR)的峰值性能与 JIT 成熟度更强。所以 Bun 快,但"快在哪"需要分场景看——这不是简单的"谁更快"。
2.2 Node.js 兼容性的"阴招":直接跑 Node 的测试套件
Bun 有一个让开发者又爱又恨的兼容策略:它主动把 Node.js 官方的测试套件拉过来自己跑,逐模块提升通过率。这意味着 http、crypto、dgram、fs 等核心模块的 Node 兼容测试通过率已经被推到 90%+ 以上。
它的兼容性哲学是:不追求 100% 字节级兼容,但追求"把你真实项目跑起来"。比如 Express 在 Bun 上能直接跑,而且官方基准里 Express 在 Bun 上的吞吐比在 Node 上快约 3 倍——因为 Bun 的 http 底层是基于高性能网络栈重写的,而不是 Node 那套。
2.3 bun: 命名空间:Bun 的"私房 API"
Bun 把原生能力挂在 bun: 前缀的模块下,避免和 Web 标准 / Node API 冲突:
bun:sqlite—— 同步、零拷贝的 SQLite 客户端;bun:ffi—— 零配置调用 C 动态库;bun:test—— 测试框架;bun:html—— 把 HTML 转成 JSX(用于框架集成);bun:jsc—— 直接操控 JavaScriptCore 内部(内存、垃圾回收洞察)。
而 1.3 引入的 bun:sql 是本文重点,下一节细说。
三、架构分析:Bun 为什么快,以及那场震惊社区的 Rust 重写
3.1 快的三层地基
Bun 的性能不是"调出来的",而是从架构地基上长出来的:
- 引擎层:JavaScriptCore 的轻量启动 + 自带字节码缓存;
- 系统层:底层用 Zig(现迁移 Rust)手写,配合 mimalloc 作为全局内存分配器,减少 malloc 碎片;文件 IO、DNS、HTTP 都走自建的高性能实现,而不是 Node 的 libuv 路径;
- 工具链层:转译器和打包器用自家 parser(基于 zig 的 parser,正在迁 Rust),能在内存里直接完成 TS/JSX → JS,没有 babel 那种多进程插件链的开销。
官方基准(注意这是 Bun 自家数据,需自己复现验证):
- 冷启动:
bun -e '...'比node -e '...'快约 4 倍; - 包安装:
bun install比npm install快约 25–30 倍; - 打包:
bun build在多数场景快于 esbuild / webpack。
3.2 Bun 1.3 的"全栈化"三连击
1.3 被称为 "Bun 史上最大版本",核心是把 Bun 从"高性能运行时"升级成"一站式全栈方案":
- 统一数据库 API
bun:sql:一套 API 同时支持 PostgreSQL、MySQL/MariaDB、SQLite,靠连接串切换,SQL 与参数化语法一致; - 零配置前端开发:内置 HMR(热重载),底层用各平台原生文件监听(macOS 的 kqueue、Linux 的 inotify、Windows 的 ReadDirectoryChangesW),比 JS 实现的文件监听快 10 倍以上;支持 React Fast Refresh,通过
import.meta.hot自定义热更新; - 内置 Redis 客户端 + 既有 S3 客户端,把"后端要连的服务"也一并收编。
3.3 那场 Rust 重写:为什么,以及怎么做到的
这是 2026 年最炸裂的工程事件之一。Jarred Sumner 在 5 月 11 日的推文原文大意是:
"Bun v1.3.14 明天发布。如果我们合并 Rust 重写版本,那这将是 Zig 的最后一个版本。"
为什么要从 Zig 迁到 Rust? 核心原因是可靠性。Sumner 公开表示:Zig 经常出现内存错误(memory bug)和崩溃,而且很难彻底修复;Rust 的所有权系统和借用检查器能在编译期就挡住 dangling pointer、buffer overflow、数据竞争这类问题。对一个每天处理数十亿次请求的 JS 运行时来说,这种"编译期保证"的价值难以估量。
怎么做到的? 几个关键事实:
- 这次重写大量借助 Claude Code 完成,涉及约 96 万到 100 万行代码;
- 从 "代码跑不起来" 到 "通过既有测试套件 99.8%(Linux x64 glibc)",大约只花了 六天;
- 迁移是增量式的:先以 draft batch 形式合入底层模块(如
ConcurrentTask、全局分配器调优、source map 热路径用SmallVec栈上暂存),逐步替换,而不是一次性推倒重来; - GitHub 上能看到对应的合并 PR(如
Rewrite Bun in Rust),perf 相关 commit 显示团队在迁移的同时还在抠性能细节(mimalloc 的MI_NO_SET_VMA_NAME跳过 prctl、bundler worker 的 arena 复用等)。
这意味着什么? 短期看,v1.3.14 可能成为"最后一个纯 Zig 构建";长期看,Bun 的可靠性基线会被 Rust 抬高,而 AI 辅助大规模重写也第一次在"生产级基础设施"级别被验证。
但——争议也随之而来。
3.4 "你管得太宽了":整合边界的质疑
Bun 越做越大的同时,社区出现了两种尖锐声音:
- "一个工具想干完所有事,是不是太多了?" 当 Bun 开始内置数据库客户端、S3、Redis、密钥管理,开发者担心它变成"无法audit 的黑盒",也担心某个内置模块质量跟不上专业库(比如
pg/aws-sdk多年沉淀的边界处理)。 - 真实的反噬案例:有知名开源项目(如
yt-dlp)以安全为由弃用了低版本 Bun;部分子项目(如Electrobun)选择解绑。这给 Bun 的统一叙事泼了冷水——整合带来的便利,和专业化带来的信任,是此消彼长的。
我的判断:Bun 的"全栈化"对个人开发者、创业团队、Demo 与原型是巨大福音;但对强合规、重审计、已有成熟基建的大厂,它会先被当成"实验性底座",而非默认选择。这很合理。
四、代码实战:一个 Bun 全栈工程的完整切片
光说架构太虚,下面用真实可跑的切片,把 Bun 的核心能力串起来。
4.1 工程骨架与脚本
{
"name": "bun-fullstack-demo",
"module": "src/index.ts",
"type": "module",
"scripts": {
"dev": "bun run --hot src/index.ts",
"build": "bun build ./public/index.html --outdir=./dist --minify",
"test": "bun test",
"start": "bun run src/index.ts"
},
"devDependencies": {
"bun-types": "latest"
}
}
bun install 会生成文本格式的 bun.lock(注意:早期是二进制 bun.lockb,1.2 起切换为文本锁文件,便于 code review 和冲突解决,且安装速度反而更快)。
4.2 HTTP 服务 + WebSocket(一个二进制搞定)
// src/index.ts
Bun.serve({
port: 3000,
// 普通 HTTP 请求
fetch(req, server) {
const url = new URL(req.url);
if (url.pathname === "/api/health") {
return Response.json({
ok: true,
runtime: "bun",
version: Bun.version,
uptime: process.uptime(),
});
}
if (url.pathname === "/api/echo") {
const body = await req.json().catch(() => ({}));
return Response.json({ youSent: body });
}
// 把连接升级为 WebSocket
if (url.pathname === "/ws") {
const upgraded = server.upgrade(req);
if (upgraded) return undefined; // 已被 WebSocket 接管
return new Response("upgrade failed", { status: 500 });
}
return new Response("Not Found", { status: 404 });
},
// WebSocket 生命周期
websocket: {
open(ws) {
ws.send("connected");
},
message(ws, data) {
ws.send(`echo @ ${new Date().toISOString()}: ${data}`);
},
close(ws) {
console.log("client left");
},
},
});
console.log("🚀 listening on http://localhost:3000");
注意这里的 fetch(req, server) 双参数签名:第二个 server 专门用于 server.upgrade() 做 WebSocket 升级。这是 Bun 相比"裸 Node http"更顺手的地方之一。
4.3 本地存储:bun:sqlite 同步 API
import { Database } from "bun:sqlite";
const db = new Database("app.db", { create: true });
db.run(`
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
views INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
// 参数化插入(? 占位,杜绝 SQL 注入)
const insert = db.query(
"INSERT INTO posts (title, views) VALUES (?, ?)"
);
insert.run("深入理解 Bun 1.3", 0);
// 查询
const recent = db.query(
"SELECT * FROM posts ORDER BY id DESC LIMIT ?"
);
console.log(recent.all(10));
// 事务批量写入
const insertMany = db.query("INSERT INTO posts (title) VALUES ($title)");
const tx = db.transaction((titles: string[]) => {
for (const t of titles) insertMany.run({ $title: t });
});
tx(["文章A", "文章B", "文章C"]);
bun:sqlite 是同步的(基于 SQLite 原生同步 API + Bun 的事件循环友好调度),写起来比 better-sqlite3 还省心,且零原生编译烦恼。
4.4 统一数据库 API:bun:sql(PG / MySQL / SQLite 一套搞定)
这是 1.3 的王炸。同样一套 API,换连接串即可切换数据库:
import { sql, SQL } from "bun";
// 统一 API:差异仅在连接串
const pg = new SQL("postgres://user:pass@localhost:5432/app");
const mysql = new SQL("mysql://user:pass@localhost:3306/app");
const sqlite = new SQL("sqlite://data.db");
const username = "alice";
// 标签模板 + 自动参数化,从根本上防注入
const rows = await sql`
SELECT id, name, role
FROM users
WHERE username = ${username}
AND active = TRUE
`;
console.log(rows);
await pg.close();
对全栈开发者而言,这意味着:业务代码不需要因为"今天用 PG、明天换 MySQL"而重写。迁移成本被压到了一行连接串。
4.5 对象存储:Bun.s3(不再需要 aws-sdk)
Bun.s3 的 API 刻意设计得和 Response / Blob / Bun.file 一致,让"从 S3 读"和"从本地读"体验无差别:
// 配置来自标准 AWS 环境变量:
// AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_REGION / S3_BUCKET
// 上传(直接写,无需先下载到内存)
await Bun.s3.file("uploads/avatar.png").write(
Bun.file("./avatar.png")
);
// 下载到本地:Bun.write 已原生支持 S3 源
await Bun.write("./downloaded.png", Bun.s3.file("uploads/avatar.png"));
// 列举前缀
for await (const obj of Bun.s3.list("uploads/")) {
console.log(obj.key, obj.size);
}
官方基准称其 S3 操作比基于 AWS SDK 的 Node 应用快约 5 倍——因为少了 SDK 的层层封装与中间件。
4.6 测试:bun test(内置,零配置)
// src/calc.test.ts
import { test, expect, describe } from "bun:test";
function add(a: number, b: number) {
return a + b;
}
describe("add", () => {
test("正整数相加", () => {
expect(add(1, 2)).toBe(3);
});
test("负数", () => {
expect(add(-1, -1)).toBe(-2);
});
test.todo("边界情况待补充");
});
常用姿势:
bun test # 运行全部
bun test src/calc.test.ts # 单文件
bun test --coverage # 覆盖率
bun test --reporter=junit > report.xml # 接 CI
bun test 支持快照、内联快照、JUnit / LCOV 报告,基本覆盖了 Jest 的日常用法,却不需要装 Jest。
4.7 打包与构建:bun build
// build.ts
await Bun.build({
entrypoints: ["./src/client.tsx"],
outdir: "./dist",
target: "browser",
minify: true,
sourcemap: "external",
// 原生识别 CSS / 图片 / 字体等资源
});
也可以直接对 HTML 入口打包(前端零配置):
bun build ./public/index.html --production --outdir=./dist
Bun 会在构建时自动调用原生转译器处理 React / Vue 代码,无需额外 babel / webpack 配置。
4.8 进阶:零开销 FFI 与编译期宏
Bun 还有两个"硬核"能力,展示它的底层野心:
(1)bun:ffi 零配置调用 C 库:
import { dlopen, FFIType, suffix } from "bun:ffi";
const lib = dlopen(`libmath.${suffix}`, {
add: {
args: [FFIType.f64, FFIType.f64],
returns: FFIType.f64,
},
});
console.log(lib.symbols.add(1.5, 2.5)); // 4
(2)Bun 宏:把代码在编译期跑掉
// 在编译期读取 SQL 文件并内联为字符串,避免运行时 IO
import { readSQL } from "./macro" with { type: "macro" };
const query = readSQL("./queries/user.sql");
// macro.ts
import { readFileSync } from "fs";
export function readSQL(path: string) {
return readFileSync(path, "utf8");
}
宏函数的函数体在编译期执行,返回值被直接内联进产物——这是把"构建时计算"做成语言级特性的思路,和 Zig 的 comptime 哲学一脉相承。
五、性能优化:基准、原理与生产迁移
5.1 自己复现基准,别只信官方数字
任何"快 X 倍"都得自己跑一遍。几个零成本复现脚本:
# 冷启动
time bun -e 'console.log("hi")'
time node -e 'console.log("hi")'
# 包安装(用同一个真实工程)
time bun install
time npm install
# HTTP 吞吐(用 bun 自带的简易压测或 autocannon)
bunx autocannon -c 100 -d 10 http://localhost:3000/api/health
经验结论(我自己在中等规模 API 工程上的观察,非官方):
- 冷启动 / CLI 场景:Bun 优势明显,Serverless 下能显著降本;
- 短连接 HTTP API:Bun 的
Bun.serve吞吐普遍高于 Node + Express; - 重计算 / 长连接 / 巨型 SSR:差距收窄,甚至 V8 在某些热点上反超。
所以选型别一刀切:Bun 的甜区是"多、小、快"的服务(边缘函数、API 网关、CLI 工具、原型),而不是"单点重负载"的传统巨石应用。
5.2 把 Node / Express 项目迁到 Bun 的实操清单
- 先跑通,再优化:把
package.json的scripts从node换成bun run,多数纯 JS/TS 项目能直接起; - 替换原生依赖:把
better-sqlite3、pg/mysql2(如仅做基础 CRUD)、aws-sdk逐步换成bun:sqlite/bun:sql/Bun.s3,减少原生编译与体积; - 移除 babel / webpack:用
bun build接管;TS 配置里module设为esnext,moduleResolution设为bundler; - 警惕 Node 专属 API:
process.binding、require的某些黑魔法、特定 N-API 原生模块可能不兼容,需要逐个验证; - 压测对比:迁移后用 autocannon 跑一遍,记录 P99 与内存,再决定是否全量切。
5.3 性能调优的五个着眼点
- 减少序列化:能用
Bun.file直接流式返回,就别await resp.text()再Buffer.from; - 用同步 SQLite 替代网络往返:配置、元信息、会话等小数据,本地 SQLite 比远程 KV 快一个量级;
- 复用
db.query预编译语句:别每次请求拼新语句; - WebSocket 代替轮询:Bun 的 WS 实现轻量,长连接场景省资源;
- 生产构建务必
--minify+ 外部 sourcemap:既保体积又保可调试性。
六、总结与展望:Bun 到底值不值得 All-in
把 Bun 的 2026 摆在桌面上,我的判断是审慎乐观:
值得跟进的理由:
- 开发者体验断层领先:一个二进制解决 runtime + 包管理 + 打包 + 测试,新项目从 0 到能跑的时间被压到极致;
- 性能甜区真实存在:冷启动、包安装、轻量 HTTP 这三块,Bun 不是"微优化",而是数量级差异;
- 全栈 API 收编降低心智负担:
bun:sql、Bun.s3、bun:sqlite让"写个带存储的全栈服务"从"装五个库"变成"写几行"; - Rust 重写抬高可靠性基线:从 Zig 的"内存 bug 难修"到 Rust 的"编译期保证",这对一个基础设施级项目是长期利好;
- Anthropic 的押注:意味着 Bun 会持续拿到 AI 原生工具链的红利与资源。
需要警惕的风险:
- 整合边界过宽:内置模块能否追上专业库多年的边界处理,需要时间验证;
- 兼容性并非 100%:真实项目里总有 Node 专属黑魔法会绊住你;
- 治理与节奏争议:半年内从"Zig 特立独行"到"Rust 重写",再叠加"加入 Anthropic",节奏激进,部分社区已用脚投票(如 yt-dlp 弃用);
- AI 重写的"可维护性"未知数:六天百万行、99.8% 通过率很燃,但长期可维护性、可读性、团队接手成本,要等社区检验。
15 条生产踩坑清单
- 不要盲目全量替换 Node:先在非核心服务试点,跑满一周再决定;
bun:sqlite是同步的:高并发写场景注意锁竞争,必要时用 WAL 模式;bun:sql不同数据库方言有差异:分页、JSON 函数、自增语法别假设一致;Bun.s3配置走环境变量:别把密钥写进代码,用Bun.secrets或 CI Secret;- 低版本 Bun 有已知安全坑:生产务必锁定 v1.3.x 及以上;
- 原生 N-API 模块可能不兼容:
bcrypt、sharp等需逐个验证或找替代; bun.lock是文本锁:升级 Bun 后记得重新bun install刷新;- HMR 在复杂状态里有边界:有状态模块用
import.meta.hot显式处理 dispose; - WebSocket 升级必须返回
undefined:忘了返回会导致连接挂起; Bun.build默认不打包 node_modules:需显式配置 external / bundle;- FFI 调用注意 ABI 与平台后缀:用
suffix自动适配.dylib/.so/.dll; - 宏函数体在编译期执行:别在里面写有副作用或依赖运行时的逻辑;
- 压测前先warm-up:JSC 的 JIT 需要预热,冷压测会低估性能;
- 生产构建开
--minify但保留 sourcemap:线上排障靠它; - 关注 Rust 重写后的版本稳定性:v1.3.14 这类过渡版本,先观察一个 minor 再上生产。
写在最后
Bun 的故事,本质上是一个关于**"整合 vs 专注"**的永恒 engineering 辩题,在 2026 年的一次激进作答。它用 JavaScriptCore 和 Zig/Rust 把"快"做成了基础设施,又用 All-in-One 把"省心"做成了产品体验;而那场 AI 驱动的百万行 Rust 重写,则让"重写一个生产级运行时"第一次看起来不再是不可能的任务。
我不会鼓动你明天就把公司所有 Node 服务换成 Bun——那不负责。但我强烈建议你:新项目、CLI、边缘函数、内部工具,从今天起默认试试 Bun。当你体验到 bun install 几秒完成、bun test 零配置跑通、bun:sql 一套代码打通 PG 和 MySQL 的那一刻,你可能就回不去那个要装 eight 个工具链的 world 了。
毕竟,工具存在的意义,就是让正确的事变得理所当然地简单。