关于 bun-api
bun-api 是面向 Bun 项目开发者和编码 Agent 的技能,介绍 Bun 原生 API、版本相关行为,以及编写复杂代码前如何查阅 Bun 随附文档。
主要功能
- 01Bun 原生 API 使用指南
- 02Bun 1.4.x 版本说明
- 03随附 API 文档索引
- 04运行时相关迁移提示
- 05脚本与服务任务指南
适用场景
- 01为项目脚本选择 Bun API
- 02核对 Bun 补丁版本间的行为
- 03在 bun-types 中查找 API 参考
- 04编写 HTTP、网络或数据库代码
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dmythro/ agent-skills --skill bun-api安装后在 Claude Code 中输入/bun-api确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/file-io.mdhashing.mdhttp-server.mdimage.mdmigration-1.4.mdnetworking.mdredis-client.mds3-client.mdshell-and-process.mdsql-client.mdsqlite-and-data.mdutilities.mdwebview.md详细介绍
Bun 运行时 API
Bun 原生运行 TypeScript——无需 tsc 编译、无需 ts-node,也无需构建步骤。直接使用 bun file.ts 运行任意 .ts 文件;运行时不会进行类型检查,因此请使用 bun check(v1.4.3+,参见 bun-cli 技能)进行检查。请使用 Bun 的原生 API,而不是 Node.js 的等效 API——它们速度更快、使用更便捷,而且无需额外依赖。
重要:在 Bun 项目中(包含 bun.lock、bun.lockb、bunfig.toml,或在 devDependencies 中包含 bun-types / @types/bun),始终使用 Bun 运行脚本(bun file.ts,而不是 node file.ts),并优先使用 Bun 原生 API,而不是 Node.js 的等效 API。混用运行时会引发细微错误,导致不必要的重试。
已针对 Bun v1.4.4 验证(2026-10-22)。功能标注了引入它们的版本(v1.4+、v1.4.1+、v1.4.2+、v1.4.3+、v1.4.4+)。如果某个版本更改了现有行为,则会同时说明新旧行为,确保本指南对旧项目也适用——依赖带版本标注的项目之前,请先检查 bun --version。
版本指南:各个 1.4.x 版本的变更
| 版本 | 新增 | 现有代码行为变更 | 适合在以下情况下升级 |
|---|---|---|---|
| 1.4.0 (2026-08-20) | Bun.XML、TOML.stringify()、Bun.secrets、spawn({ cgroup })、{ dir } 路由、textStream()、fetch({ compress })、ML-DSA / ML-KEM、支持背压的原生 Web Streams | Bun.cron 使用本地时间,重复的标头会合并为 ", ",启用 Temporal,目标 Node 26(NODE_MODULE_VERSION 147),Bun.connect / Bun.listen 的 rejectUnauthorized: true,MySQL 日期按 UTC 解码,fetch 网络错误为 TypeError | 你需要 1.4 API——请先检查 cron 计划、自签名开发服务器和 MySQL 日期偏移 |
| 1.4.1 (2026-09-04) | Bun.serve({ http2 })、流式 Bun.write(path, response)、客户端 WebSocket#pause()、crypto.argon2Sync()、Unix 套接字 keep-alive | fetch() 根据 URL 主机而不是 Host 标头验证 TLS;localhost 无需系统解析器即可解析 | 不要将此版本作为目标:AsyncLocalStorage 值会泄漏,且 Worker 的 'online' 会在其首条消息发出后才触发——请使用 1.4.2 或更高版本 |
| 1.4.2 (2026-09-05) | 无(错误修复版本) | .json() 会以 JSON.parse 的错误消息拒绝;可解码 CMYK / YCCK JPEG | 你正在使用 1.4.1 |
| 1.4.3 (2026-10-10) | Bun.FetchSession、Bun.ModuleGraph、CompressionStream 压缩级别、If-Range、fetch({ proxy: false }) | 每个请求都设置 checkServerIdentity 会导致每个请求都新建连接,未等待的、被拒绝的 fetch() 会以 1 退出,适用 ALL_PROXY 和更宽泛的 NO_PROXY 语法,代码生成标志会强制执行,sql.begin() 会拒绝已回滚的事务 | 你需要按客户端设置 TLS 或代理,或遇到了 1.4.1 时代的错误(promisify(setTimeout)、keep-alive ECONNRESET) |
| 1.4.4 (2026-10-22) | bun:sqlite 函数和更新钩子、SQL.camel 转换、sql.json()、可正常使用的 query.cancel()、PostgreSQL COPY 流、服务端 ws.pause()、error(error, ws)、Bun.Glob 中的 extglob、createWebSocketStream() | WebSocket 关闭代码(1005、1006、1001)和 ws 事件,glob 中 *(...) / {1..3} 的含义,mTLS 需要 requestCert,多语句 SQLite 错误会抛出,Bun.hash() 不带数据会抛出错误 | 你使用 bun:sqlite、Bun.SQL、ws 或 WebSocket 服务器——如果要流式处理 JSONL,请离开 1.4.3 |
默认使用最新补丁版本。 每个补丁都会修复之前版本引入的回归问题(详见 references/migration-1.4.md 中各版本对应的条目),因此固定使用较旧的“已知良好”1.4.x 版本会保留已知问题。升级代码库之前,请阅读中间每个版本的“现有代码行为变更”列:升级可能要求进行的修改都列在其中。
先阅读 Bun 自带的文档
Bun 将完整文档打包在 bun-types 中,版本与运行时匹配。
在任何安装了 bun-types 或 @types/bun 的项目中:
node_modules/bun-types/docs/**/*.mdx # full docs, plus ~180 task-shaped guides/
node_modules/bun-types/*.d.ts # richest API surface (bun.d.ts, serve.d.ts, sql.d.ts)
node_modules/bun-types/CLAUDE.md # Bun's own agent rules
编写复杂的 Bun 代码前,请先查阅这些文档。 本技能介绍该使用哪个 API; 随附文档则说明确切的签名和选项。
-
依赖
bun-types,而不是@types/bun。 每个 Bun 版本都附带bun-types, 其中包含文档和类型。@types/bun的更新总是落后于 Bun 版本,通常会晚一天或更久, 但bun init会将其添加为latest,因此最新 API 无法通过类型检查(TS2339、TS2353)。在@types/bun旁添加bun-types只能修复文档路径——类型检查 仍会使用@types/bun嵌套且固定版本的副本。请同时替换二者,然后比较bun --version与node_modules/bun-types/package.json:bun remove @types/bun bun add -d bun-types@$(bun --version) # then "types": ["bun-types"] in tsconfig.json -
通过明确路径打开。 启用 Bun 的全局虚拟存储后,
node_modules/bun-types是一个符号链接:find node_modules -name '*.mdx'和rg <pattern> node_modules不会返回 任何结果,而find node_modules/bun-types/docs -name '*.mdx'可以正常工作。 -
切勿编辑
node_modules/下的文件。 使用全局存储时,机器上的每个项目都共享同一个 inode—— 在其中写入会影响所有项目。请使用bun patch。 -
未安装? 同一路径也可在线访问:
docs/runtime/sql.mdx对应https://bun.com/docs/runtime/sql。
| 任务 | 文档路径(位于 node_modules/bun-types/docs/ 下) |
|---|---|
| HTTP 服务、路由、WebSocket | runtime/http/server.mdx、runtime/http/routing.mdx、runtime/http/websockets.mdx |
fetch、TCP、UDP、DNS | runtime/networking/fetch.mdx、runtime/networking/tcp.mdx、runtime/networking/udp.mdx、runtime/networking/dns.mdx |
| 文件 I/O、流、二进制数据 | runtime/file-io.mdx、runtime/streams.mdx、runtime/binary-data.mdx |
| Shell、子进程、PTY | runtime/shell.mdx、runtime/child-process.mdx |
| SQL、SQLite、Redis、S3 | runtime/sql.mdx、runtime/sqlite.mdx、runtime/redis.mdx、runtime/s3.mdx |
| 解析器 | runtime/json5.mdx、runtime/jsonl.mdx、runtime/xml.mdx、runtime/toml.mdx、runtime/yaml.mdx、runtime/markdown.mdx、runtime/file-types.mdx |
| 图像、WebView、cron、密钥、归档 | runtime/image.mdx、runtime/webview.mdx、runtime/cron.mdx、runtime/secrets.mdx、runtime/archive.mdx |
| 哈希、工具函数、semver、glob、Cookie、CSRF | runtime/hashing.mdx、runtime/utils.mdx、runtime/semver.mdx、runtime/glob.mdx、runtime/cookies.mdx、runtime/csrf.mdx |
| 应用实例、字符串求值锁定(v1.4.3+) | runtime/module-graph.mdx、runtime/code-generation-from-strings.mdx |
| Node.js 兼容性 | runtime/nodejs-compat.mdx |
适用场景
- 生成文件、解析数据、运行迁移的脚本
- 文件处理和转换工作流
- Shell 脚本和自动化
- 使用 SQLite(
bun:sqlite)执行数据库操作 - 通过连接 URL 执行数据库查询——项目在
.env或环境中配置了DATABASE_URL(PostgreSQL、MySQL、SQLite,通过Bun.sql()) - S3 存储操作——项目配置了
AWS_ACCESS_KEY_ID,或使用兼容 S3 的存储(Bun.s3) - Redis/Valkey 缓存和发布/订阅——项目配置了
REDIS_URL或VALKEY_URL(Bun.redis) - Bun 项目中的任何脚本任务
HTTP 服务器(Bun.serve)
内置 HTTP 服务器,可替代 Express、Fastify 或 http.createServer。
优先使用 routes,而不是手动解析 URL——它支持参数、按方法处理请求,并可实现零分配的静态响应。对于未匹配的请求,则回退到 fetch。
const server = Bun.serve({
port: 3000,
routes: {
'/health': new Response('OK'), // static, zero-allocation
'/api/users/:id': req => Response.json({ id: req.params.id }),
'/api/posts': { // per-method handlers
GET: () => Response.json(listPosts()),
POST: async req => Response.json(await req.json()),
},
'/static/*': { dir: './public' }, // serve a directory (v1.4+)
},
fetch(req: Request): Response | Promise<Response> { // unmatched requests
return new Response('Not Found', { status: 404 })
},
error(error: Error): Response {
return new Response(`Error: ${error.message}`, { status: 500 })
},
})
console.log(`Listening on ${server.url}`)
路由优先级:精确匹配 > :param > * > 全局 /*。已注册的 '/*' 路由会捕获所有未匹配的路径,因此只有在不存在 '/*' 路由时才会运行 fetch——请选择其中一种作为回退方式,不要同时使用。处理程序接收 BunRequest(包含 params 和 cookies 的 Request)。
主要方法:server.stop()、server.reload()(热替换处理程序)、server.requestIP(req)、server.upgrade(req)(WebSocket)。
HTTP/2(v1.4.1+,实验性)。 http2: true 会在同一端口上提供 HTTP/2 和 HTTP/1.1,并使用相同的 routes 和 fetch:TLS 上的 ALPN 会选择协议;以 HTTP/2 前言开头的明文连接(curl --http2-prior-knowledge、node:http2)则会使用 HTTP/2。http1: false 会拒绝 HTTP/1.x 客户端。server.upgrade()(WebSockets)和响应尾部字段仅支持 HTTP/1.1,因此目前还不能通过它运行 gRPC。
文件响应可安全续传(v1.4.3+)。 Bun.file() 响应体和 { dir } 路由已经会针对 Range 返回 206;现在也会遵循 If-Range。只有当 If-Range 与响应所携带的 Last-Modified 日期或强 ETag 匹配时,才会发送范围响应(Bun 不会为 Bun.file() 响应设置 ETag——请自行添加);其他任何 If-Range 值都会返回完整的 200。{ dir } 路由的弱 ETag 永远不会匹配。Bun 1.4.2 会忽略 If-Range 并始终发送范围响应。
WebSockets(1.4.4 中的变更)。 在服务器套接字上使用 ws.pause() / ws.resume() / ws.isPaused,可停止读取发送速度超过消费速度的客户端数据,并暂停空闲超时。websocket.error(error, ws) 会接收其处理程序抛出错误的套接字(1.4.3 不会传入套接字),且所有处理程序均为可选。关闭代码遵循协议:客户端调用不带代码的 close() 时,两端都会报告 1005(1.4.3 为 1000);而服务器端的 ws.close() 仍会发送 1000;server.stop(true) 会发送 1001 Server closed(1.4.3 为 1006);协议错误则会以 1002 / 1007 / 1009 关闭(参见发行说明)。在调用 server.upgrade() 前,请将 Origin 与允许列表进行比对——同源策略不适用于 WebSocket 握手。
mTLS(1.4.4 中的变更)。 Bun.serve / Bun.listen / node:tls 服务器只有在设置 requestCert: true 时才会请求客户端证书;单独设置 ca 不再会触发该行为(1.4.3 在设置 ca 时总会发送证书请求)。双向 TLS 需要同时设置两者。
参考:TLS、WebSocket 升级、流式响应、静态文件服务和 1.4 行为变更,请参阅
references/http-server.md。完整 API 参见node_modules/bun-types/docs/runtime/http/server.mdx和runtime/http/routing.mdx。
TCP / UDP 套接字
用于非 HTTP 协议的原始套接字——TCP 使用 Bun.listen() / Bun.connect(),UDP 使用 Bun.udpSocket(),此外还有内置的 WebSocket 客户端和 fetch()。
const server = Bun.listen({
hostname: '127.0.0.1',
port: 8080,
socket: {
open(socket) { socket.write('welcome\n') },
data(socket, data) { /* Buffer */ },
},
})
WebSocket 客户端(在 1.4.4 中更改)。 close 会在服务器发送 Close 帧后触发,与浏览器中的行为一致:以 ws.close() 结束的脚本需要再进行一次往返才能退出;根据发行说明,如果服务器始终不响应,则 30 s 后会收到 1006(BUN_CONFIG_WS_CLOSE_TIMEOUT;ws.terminate() 会立即关闭)。连接失败时会触发 error(带有 event.error.code,例如 ECONNREFUSED),随后触发 close,其代码为 1006 且 reason 为空。内置的 ws 包现在与 Node 上的 npm ws 行为一致:'error' 会收到带有 .code 的 Error,'close' 会收到 Buffer 类型的原因,没有监听器时触发 'error' 会导致进程崩溃,并且 createWebSocketStream() 可用——请为每个 ws 套接字添加 'error' 监听器。
参考:TCP/UDP 处理器、Unix 套接字、WebSocket 客户端(
ws+unix://、关闭代码、ws包)以及fetch()传输选项(HTTP/2、HTTP/3、代理、系统 CA),请参阅references/networking.md。
fetch() 会话和代理(v1.4.3+)
Bun.FetchSession 可为一组请求设置独立的 TLS、代理和 keep-alive 选项,并使用专属连接池。请使用它,而不要使用 undici 的 Agent / dispatcher:Bun 内置的 undici 会导出这些类,因此导入可以成功,但 fetch() 会忽略 dispatcher。
const session = new Bun.FetchSession({
tls: { ca: await Bun.file('corp-ca.pem').text() },
proxy: { url: 'http://proxy.internal:8080' },
keepAlive: { idleTimeout: 30, maxIdleSockets: 8 }, // false: a new connection per request
})
const client = new SomeClient({ fetch: session.fetch }) // bound -- hand it to any client
await fetch('https://api.example.com/v1', { session }) // the same, through the global fetch
session.close() // closes idle connections; stays usable
- 会话之间以及会话与普通
fetch()之间绝不共享连接。请求选项会覆盖会话选项,而请求的tls会整体替换会话的tls。 - 在会话上固定证书,而不是在请求上固定。 每个请求上的
tls.checkServerIdentity都会建立专用 TLS 连接,并在响应后将其关闭(3 个请求:3 次握手;1.4.2 会复用连接)。在会话上设置时,它会在每个连接上运行一次,之后该连接会进入连接池。 session.fetch没有preconnect;如果某个选项的类型为typeof fetch,请传入session.fetch as typeof fetch。
代理选择。 无论 HTTP_PROXY / HTTPS_PROXY / ALL_PROXY 的值如何,proxy: false 都会直接连接。如果未设置特定协议的变量,现在会应用 ALL_PROXY(1.4.2 会忽略它)。NO_PROXY 支持 *.example.com、CIDR 网段(10.0.0.0/8)、裸 IPv6 地址和 host:port,并且也会绕过显式设置的 proxy,除非该代理设置了 respectNoProxy: false。如果代理拒绝 CONNECT,fetch() 会以 ERR_PROXY_TUNNEL 拒绝;而 1.4.2 会将代理的回复当作源站的回复处理:
try {
await fetch(url, { proxy: { url: 'http://proxy.internal:8080', respectNoProxy: false } })
} catch (e: any) {
if (e.code === 'ERR_PROXY_TUNNEL') console.error(e.status, e.headers.get('proxy-authenticate'))
}
参考:会话选项、
NO_PROXY语法和checkServerIdentity规则,请参阅references/networking.md;另请参阅node_modules/bun-types/docs/runtime/networking/fetch.mdx。
文件 I/O
读取文件
// Create a BunFile reference (lazy, no read yet)
const file = Bun.file('path/to/file.txt')
// Read contents
const text = await file.text() // string
const json = await file.json() // parsed JSON
const bytes = await file.arrayBuffer() // ArrayBuffer
const stream = file.stream() // ReadableStream
const blob = await file.blob() // Blob
// File metadata
file.size // Size in bytes
file.type // MIME type (auto-detected)
file.name // File path
await file.exists() // Boolean
// Read from URL
const remote = Bun.file('https://example.com/data.json')
写入文件
// Write string
await Bun.write('output.txt', 'content')
// Write from BunFile (efficient copy)
await Bun.write('copy.txt', Bun.file('original.txt'))
// Write JSON
await Bun.write('data.json', JSON.stringify(data, null, 2))
// Write Uint8Array / ArrayBuffer
await Bun.write('binary.dat', new Uint8Array([1, 2, 3]))
// Write a Response body -- streamed to disk (v1.4.1+; the whole body was buffered before)
await Bun.write('page.html', await fetch('https://example.com'))
// Write to stdout
await Bun.write(Bun.stdout, 'Hello\n')
标准 I/O
Bun.stdin // BunFile for stdin
Bun.stdout // BunFile for stdout
Bun.stderr // BunFile for stderr
// Read all of stdin
const input = await Bun.stdin.text()
// Stream stdin line by line
for await (const chunk of Bun.stdin.stream()) {
// process chunk (Uint8Array)
}
常见模式
// JSON transform
const data = await Bun.file('input.json').json()
data.version = '2.0.0'
await Bun.write('output.json', JSON.stringify(data, null, 2))
// File generation from template
const template = await Bun.file('template.html').text()
const output = template.replace('{{title}}', 'My Page')
await Bun.write('index.html', output)
// Check if file exists before reading
const file = Bun.file('config.json')
if (await file.exists()) {
const config = await file.json()
}
参考:BunFile 接口、写入方法重载、流式处理、MIME 检测和文件监视,请参阅
references/file-io.md。
Shell 和进程执行
Bun.$(标记模板 Shell)
运行 Shell 命令的主要方式。返回一个包含输出的 Promise。
import { $ } from 'bun'
// Basic execution
const result = await $`ls -la`
console.log(result.text()) // stdout as string
// With interpolation (auto-escaped)
const dir = 'my folder'
await $`ls ${dir}` // Safe: "my folder" is properly quoted
// Output methods
const output = await $`echo hello`
output.text() // "hello\n"
output.json() // Parse stdout as JSON
output.lines() // string[] (splits on newlines)
output.bytes() // Uint8Array
output.blob() // Blob
output.exitCode // number
output.stderr // Buffer
// Piping
await $`cat file.txt | grep pattern | wc -l`
// Quiet mode (suppress stdout)
await $`npm install`.quiet()
// No-throw mode (don't throw on non-zero exit)
const result = await $`command-that-might-fail`.nothrow()
if (result.exitCode !== 0) {
console.error('Failed:', result.stderr.toString())
}
// Combined
await $`risky-command`.quiet().nothrow()
// Environment variables
await $`echo $HOME`.env({ HOME: '/custom' })
// Working directory
await $`ls`.cwd('/tmp')
// Redirect to file
await $`echo hello > output.txt`
await $`cat < input.txt`
// Pipe between commands
const input = Buffer.from('hello')
await $`cat`.stdin(input)
Bun.spawn(较低层级)
用于更精细地控制进程执行。
const proc = Bun.spawn(['command', 'arg1', 'arg2'], {
cwd: '/path',
env: { ...process.env, CUSTOM: 'value' },
stdin: 'pipe', // 'pipe' | 'inherit' | 'ignore' | BunFile | Blob | Response
stdout: 'pipe', // 'pipe' | 'inherit' | 'ignore' | BunFile
stderr: 'pipe', // 'pipe' | 'inherit' | 'ignore' | BunFile
onExit(proc, exitCode, signalCode, error) {
// Called when process exits
},
})
// Write to stdin
proc.stdin.write('input data')
proc.stdin.end()
// Read stdout
const output = await new Response(proc.stdout).text()
// Wait for completion
await proc.exited // Promise<number> (exit code)
// Kill
proc.kill() // SIGTERM
proc.kill('SIGKILL') // Specific signal
Bun.spawnSync(同步)
const result = Bun.spawnSync(['command', 'arg1'], {
cwd: '/path',
env: { ...process.env },
})
result.exitCode // number
result.stdout // Buffer
result.stderr // Buffer
result.success // boolean
参考:完整的 $ API、spawn 选项、IPC 和信号处理,请参阅
references/shell-and-process.md。
Glob 模式匹配
const glob = new Bun.Glob('**/*.ts')
// Async iteration
for await (const path of glob.scan({ cwd: './src', onlyFiles: true })) {
console.log(path)
}
// Sync iteration
for (const path of glob.scanSync('./src')) {
console.log(path)
}
// Test if a path matches
glob.match('src/index.ts') // true
glob.match('README.md') // false
// Scan options
glob.scan({
cwd: './src', // Directory to scan (default: '.')
dot: false, // Include dotfiles (default: false)
onlyFiles: true, // Skip directories (default: true)
absolute: false, // Return absolute paths (default: false)
followSymlinks: false, // Follow symlinks (default: false)
})
// Extglob and brace ranges (v1.4.4+)
new Bun.Glob('**/!(*.test).ts').match('src/cart.ts') // true; src/cart.test.ts -> false
new Bun.Glob('src/@(app|lib)/**/*.ts').match('src/app/a.ts') // true
new Bun.Glob('shard-{1..3}.json').match('shard-2.json') // true; also {01..10}, {a..e}, {1..9..2}
1.4.4 中的变更——glob 语法。 在 Bun 使用 glob 的所有地方,?(...)、*(...)、+(...)、@(...) 和 !(...) 都是 extglob 运算符,{1..3} 是范围,包括 Bun.Glob、--filter,以及 package.json 中的 workspaces、files 和 sideEffects("workspaces": ["packages/!(internal)"] 可正常使用)。1.4.3 会按字面匹配这些内容,因此 *(1).txt 会匹配 copy(1).txt;现在它表示“零个或多个 1,后接 .txt”——若要匹配字面内容,请写成 *[(]1).txt。没有前缀的括号仍按字面处理(app/(marketing)/**);Bun Shell 对引号中的文本和 ${} 值仍按之前的方式按字面处理;而 {src/**,lib/**} 现在会匹配 src/a/b.ts(1.4.3 会把花括号内的 ** 当作 *)。
环境变量和参数
Bun.env.NODE_ENV // Environment variable (same as process.env)
Bun.env.DATABASE_URL // Typed access
Bun.argv // string[] — [bunPath, scriptPath, ...args]
// Equivalent: process.argv
Bun.main // Absolute path to the entry point script
import.meta.dir // Directory of current file
import.meta.file // Filename of current file
import.meta.path // Full path of current file
import.meta.dirname // Same as import.meta.dir (Node.js compat)
import.meta.filename // Same as import.meta.path (Node.js compat)
SQL 客户端(Bun.sql)——PostgreSQL、MySQL、SQLite
内置 SQL 客户端,可通过连接 URL 查询数据库。零依赖、带标签的模板字面量、自动预处理语句、连接池。当项目的 .env 或环境中存在 DATABASE_URL 时使用。
import { sql, SQL } from "bun"
// Default instance -- auto-connects using DATABASE_URL from environment
const users = await sql`SELECT * FROM users WHERE active = ${true} LIMIT ${10}`
// Explicit connection
const db = new SQL("postgres://user:pass@localhost:5432/mydb")
const results = await db`SELECT * FROM users`
// MySQL
const mysql = new SQL("mysql://user:pass@localhost:3306/mydb")
使用对象辅助方法插入 / 更新
const user = { name: "Alice", email: "[email protected]" }
// Insert -- expands object to (column1, column2) VALUES (val1, val2)
const [newUser] = await sql`INSERT INTO users ${sql(user)} RETURNING *`
// Bulk insert
await sql`INSERT INTO users ${sql([user1, user2, user3])}`
// Update -- expands to SET column1 = val1, column2 = val2
await sql`UPDATE users SET ${sql(updates)} WHERE id = ${userId}`
事务
await sql.begin(async (tx) => {
const [user] = await tx`INSERT INTO users (name) VALUES (${"Alice"}) RETURNING *`
await tx`INSERT INTO audit_log (action, user_id) VALUES ('created', ${user.id})`
})
// Auto-committed on success, rolled back on error
1.4.4 中的新功能
import { sql, SQL } from "bun"
// snake_case columns, camelCase code -- both directions, every adapter
const db = new SQL({ url: process.env.DATABASE_URL, transform: SQL.camel })
await db`INSERT INTO users ${db({ firstName: "Alice" })}` // INSERT INTO users ("first_name") ...
const [u] = await db`SELECT first_name FROM users` // u.firstName === "Alice"
await sql`INSERT INTO settings (data) VALUES (${sql.json(42)})` // JSON 42; a bare null stays SQL NULL
await sql`SELECT * FROM users WHERE id = ANY(${[1, 2, 3]})` // PostgreSQL: arrays bind to array types
const q = sql`SELECT pg_sleep(30)`.execute()
setTimeout(() => q.cancel(), 100) // PostgreSQL: the server stops it; q rejects
const r = await sql`SELECT id, tags FROM posts`
r.columns // [{ name, type: <OID>, ... }]; null on SQLite
r.affectedRows // rows written; 0 for a SELECT
// PostgreSQL COPY as web streams with backpressure
await Bun.file("users.csv").stream().pipeTo(sql`COPY users (id, name) FROM STDIN (FORMAT csv)`.writable())
const csv = new Response(sql`COPY users TO STDOUT (FORMAT csv, HEADER)`.readable())
1.4.4 中的变更: Bun.SQL 不再读取 PASSWORD 环境变量(请使用 PGPASSWORD、MYSQL_PASSWORD、URL 或 password);new SQL({ filename }) 无需 adapter 即会选择 SQLite(1.4.3 会尝试使用 PostgreSQL);SQLite 字符串中的多条语句会全部运行,但参数只能用于第一条语句(1.4.3 遇到第一条被认为会返回行的语句后就会停止——开头的 PRAGMA 设置语句也会被视为此类语句);SQLite 和 PostgreSQL 现在会设置 affectedRows(此前始终为 null);查询在发送前被取消时会以 ERR_SQLITE_QUERY_CANCELLED / ERR_POSTGRES_QUERY_CANCELLED / ERR_MYSQL_QUERY_CANCELLED 拒绝(1.4.3 不会结束该查询);在 SQLite 上,第二次调用 sql.begin() 会等待,而不是报错 cannot start a transaction within a transaction。关于 PostgreSQL 和 MySQL 的特性——数组绑定、COPY、服务器端取消、channelBinding、bun --hot 下的连接复用——信息来自发布说明;当时没有可用的数据库服务器来验证这些特性。
参考:连接选项、连接池管理、保存点、MySQL 特性、预处理语句配置、转换、结果元数据、
COPY和取消功能,请参阅references/sql-client.md。
S3 客户端(Bun.s3)
内置 S3 客户端,采用 Web 标准的 Blob API。零依赖,可与任何兼容 S3 的服务搭配使用(AWS S3、Cloudflare R2、MinIO 等)。当项目环境中存在 AWS_ACCESS_KEY_ID 或兼容 S3 的凭据时使用。
import { s3, write } from "bun"
// Reads credentials from AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, etc.
const file = s3.file("data.json") // Lazy reference, no network yet
// Read from S3
const data = await file.json() // Download and parse JSON
const text = await file.text() // Download as string
const stream = file.stream() // ReadableStream
// Upload to S3
await write(s3.file("output.json"), JSON.stringify(data))
// Presigned URLs (synchronous, no network request)
const url = s3.presign("report.pdf", {
expiresIn: 3600, // 1 hour
method: "PUT", // For uploads
acl: "public-read",
})
// Delete
await file.delete()
参考:自定义 S3Client、预签名选项、分段上传以及通过 Bun.serve 提供服务,请参阅
references/s3-client.md。
Redis 客户端(Bun.redis)
内置 Redis / Valkey 客户端,零依赖。当项目环境中存在 REDIS_URL 或 VALKEY_URL 时使用。
import { redis, RedisClient } from "bun"
// Default client -- reads REDIS_URL from environment
await redis.set("key", "value")
const value = await redis.get("key") // "value" | null
// With expiration
await redis.set("session", "data", "EX", 3600)
// Counter operations
await redis.incr("counter")
await redis.incrby("counter", 5)
// Hash operations
await redis.hset("user:1", "name", "Alice", "email", "[email protected]")
await redis.hget("user:1", "name") // "Alice"
// Custom client
const client = new RedisClient("redis://user:pass@host:6379")
参考:字符串、哈希、列表、集合、有序集合等所有命令,以及发布 / 订阅、管道和常见模式,请参阅
references/redis-client.md。
归档(Bun.Archive)
创建和解压 tar 包,可选使用 gzip 压缩。
// Create archive
const archive = new Bun.Archive({
"hello.txt": "Hello, World!",
"config.json": JSON.stringify({ key: "value" }),
})
await Bun.write("archive.tar", archive)
// With gzip compression -- write the BYTES, not the Archive (see gotcha below)
const compressed = new Bun.Archive(
{ "hello.txt": "Hello, World!" },
{ compress: "gzip", level: 9 } // level 1-12, default 6
)
await Bun.write("archive.tar.gz", await compressed.bytes())
// Extract (auto-detects gzip)
const tarball = await Bun.file("archive.tar.gz").bytes()
const extracted = new Bun.Archive(tarball)
await extracted.extract("./out") // -> number of entries
await extracted.extract("./out", { glob: ["src/**", "!**/*.test.ts"] })
const files = await extracted.files() // -> Map<string, File>
注意(已在 v1.4.0 至 v1.4.4 上验证): Bun.write(path, archive) 会忽略构造函数的 compress 选项,即使文件名是 .tar.gz,写出的仍是未压缩的 tar。Bun 自己的文档显示 Bun.write(path, archive) 会进行压缩——事实并非如此。请始终传入 await archive.bytes()(或 await archive.blob()),它们会正确应用 compress(上游跟踪问题:oven-sh/bun#30234)。
Archive 不可迭代——for (const [name, contents] of archive) 会抛出异常。请使用 await archive.files() 获取 Map<string, File>,或使用 await archive.extract(dir)。
参考:
node_modules/bun-types/docs/runtime/archive.mdx
JSONC(带注释的 JSON)
解析带注释和尾随逗号的 JSON——可替代 jsonc-parser 或 json5 包。
import { JSONC } from "bun"
const config = JSONC.parse(`{
// Database config
"host": "localhost",
"port": 5432, // default port
}`)
Bun 会自动对 tsconfig.json、jsconfig.json、package.json 和 bun.lock 使用 JSONC 解析。可以直接导入 .jsonc 文件:import config from "./config.jsonc"。
其他解析和实用工具(v1.3+)
import { JSON5, JSONL, XML, TOML, markdown, cron, secrets } from "bun"
// JSON5 -- superset of JSON (comments, unquoted keys, trailing commas)
const config = JSON5.parse(`{ unquoted: 'value', /* comment */ }`)
// JSONL -- newline-delimited JSON
const records = JSONL.parse('{"a":1}\n{"a":2}\n')
JSONL.parseChunk(partial) // { values, read, done, error } for streams
// XML -- SIMD parser + serializer (v1.4+), replaces fast-xml-parser / xml2js
const order = XML.parse('<order id="A1"><item>Tea</item></order>')
// { order: { "@id": "A1", item: "Tea" } } -- @attr / #text convention, values are strings
XML.parse(doc, { compact: false }) // { name, attributes, children } document tree
// TOML -- rewritten for TOML v1.1.0; stringify() added in v1.4
const cfg = TOML.parse('name = "app"')
TOML.stringify({ name: "app" })
// Markdown -- built-in CommonMark + GFM parser (replaces marked, remark, etc.)
const html = markdown.html("# Title\n\n**Bold** text.")
const ansi = markdown.ansi("# Title") // ANSI terminal output (v1.3.12+)
markdown.react(readme) // React elements (v1.3.12+)
markdown.render(src, { heading: (c, { level }) => `<h${level}>${c}</h${level}>` })
// Cron -- OS-level jobs, in-process scheduler, and expression parser
const job = cron("0 9 * * 1-5", runReport) // in-process (v1.3.12+)
const next = cron.parse("0 9 * * 1-5") // -> Date | null (NOT a string)
// Secrets -- OS credential store: Keychain / libsecret / Credential Manager (experimental)
await secrets.set({ service: "my-cli", name: "token", value: t })
const token = await secrets.get({ service: "my-cli", name: "token" }) // string | null
// ANSI-aware string utilities (replace wrap-ansi, slice-ansi npm packages)
const coloredText = "\x1b[31mHello, World!\x1b[0m"
Bun.wrapAnsi(coloredText, 80) // Wrap to column width
Bun.sliceAnsi(coloredText, 0, 5) // Grapheme-aware slice
1.4 版本变更——Bun.cron 时区。 cron.parse() 和进程内的
cron(schedule, handler) 会根据进程的本地时区读取计划。在 1.4 之前,
它们使用 UTC。传入 { tz: "UTC" } 作为最后一个参数,即可恢复旧行为:
cron("0 9 * * *", handler, { tz: "UTC" })
cron.parse("0 9 * * *", Date.now(), { tz: "UTC" })
cron.parse() 返回一个 Date;如果表达式在 8 年内没有匹配项(例如 2 月 30 日),则返回
null。cron.remove(title) 接受的是操作系统级任务的字符串标题——
不接受任务句柄。使用 job.stop() 或 using 停止进程内的任务。
1.4 版本变更——解析器更严格。 TOML.parse() 和 bunfig.toml 现在会在字符串值未加引号、键值对之间缺少换行,以及整数超出
Number.MAX_SAFE_INTEGER 时抛出 SyntaxError。JSONC.parse() 在输入无效或输入为 ""
时会抛出 SyntaxError(之前会返回 {})。YAML.parse() 遵循 YAML 1.2,因此 yes/no/on/off 是
字符串,而不是布尔值——GitHub Actions 工作流中的 on: 键会被解析为 "on"。
参考:有关所有解析和实用工具 API 的详细信息,请参阅
references/utilities.md。
SQLite(bun:sqlite)
内置 SQLite3,零依赖。适用于嵌入式/本地数据库,支持基于文件或内存的数据库。
import { Database } from 'bun:sqlite'
// Open database
const db = new Database('mydb.sqlite')
const db = new Database(':memory:') // In-memory
// Enable WAL mode (recommended)
db.exec('PRAGMA journal_mode = WAL')
// Execute statements
db.exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)')
// Prepared statements
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)')
insert.run('Alice', '[email protected]')
// Query
const select = db.prepare('SELECT * FROM users WHERE name = ?')
const user = select.get('Alice') // Single row or null
const users = select.all('Alice') // All matching rows
// Named parameters
const stmt = db.prepare('SELECT * FROM users WHERE name = $name')
stmt.get({ $name: 'Alice' })
// Transactions
const insertMany = db.transaction((users) => {
for (const user of users) {
insert.run(user.name, user.email)
}
})
insertMany([
{ name: 'Bob', email: '[email protected]' },
{ name: 'Carol', email: '[email protected]' },
])
// Close
db.close()
1.4.4 新增:JavaScript 函数和更新钩子
db.function('add2', (a, b) => a + b) // SQL function; arity = fn.length
db.query('SELECT add2(12, 4) AS sum').get() // { sum: 16 }
db.run('CREATE TABLE expenses (category TEXT, dollars INTEGER)')
db.aggregate('add_all', { start: 0, step: (total, v) => total + v }) // like sum(); inverse -> window fn
db.query('SELECT category, add_all(dollars) AS total FROM expenses GROUP BY category').all()
db.onInsert = (_db, table, rowid) => console.log(`inserted ${table} ${rowid}`) // also onUpdate, onDelete
db.onInsert = null // remove
函数中抛出的错误会从执行查询的 get() / all() / run() 中传出;其签名与 better-sqlite3 更加一致;函数和钩子都不能查询自身的 Database(This database connection is busy executing a query)。stmt.reader / stmt.readonly 会指示语句是返回行还是写入数据,db[Symbol.for('sqlite-type')] 的值为 'bun:sqlite'。
1.4.4 版本变更:
- 命名参数无论是否带前缀都能绑定,两种模式均适用:
{ name: 'A' }无需strict: true即可填入$name(1.4.3 会绑定NULL),而{ $name: 'A' }在strict: true下也能正常使用(1.4.3 会抛出Missing parameter)。 - 多语句字符串中,语句执行失败会使
db.run()/db.exec()停止并抛出错误;1.4.3 会吞掉除最后一条语句以外任何语句的运行时错误(例如UNIQUE约束冲突),并继续运行其余语句。 - 绑定
Date、Map或Promise会抛出TypeError(之前会绑定NULL),{ readonly: true, create: true }也会抛出错误,而不是以读写模式打开。 - 当
fn返回一个已被拒绝的 promise 时,db.transaction(fn)会回滚——例如,在首次await之前抛出错误的async函数(1.4.3 会提交)。事务函数应保持同步:await之后的工作会在事务之外运行。 changes只统计语句自身影响的行,不统计触发器或级联操作写入的行。
参考:有关 Database 构造函数、Statement API、事务、用户自定义函数、钩子和列类型,请参阅
references/sqlite-and-data.md。
哈希和密码
// Non-cryptographic (fast, for hash tables/checksums)
Bun.hash('input') // bigint (64-bit wyhash, fastest) -- not a number
Bun.hash.crc32('input') // number (CRC32)
Number(Bun.hash('user-123') % 16n) // shard index 0..15: mix bigints, then convert
// Cryptographic
new Bun.CryptoHasher('sha256').update('data').digest('hex')
// Password hashing (async, bcrypt by default)
const hash = await Bun.password.hash('password')
const hash = await Bun.password.hash('password', { algorithm: 'argon2id' })
const valid = await Bun.password.verify('password', hash)
// Raw Argon2 tag via node:crypto (v1.4.1+) -- interop with hashes stored as bytes, not PHC strings
import { argon2Sync, randomBytes } from 'node:crypto'
argon2Sync('argon2id', { message: 'pw', nonce: randomBytes(16), parallelism: 1, tagLength: 32, memory: 65536, passes: 3 }) // Buffer
Bun.hash() 及其 64 位算法会返回 bigint(已在 1.4.3 和 1.4.4 中确认;在 1.4.4 之前,@types/bun
将其类型标注为 number | bigint),因此 Bun.hash(key) % 16 会抛出 TypeError。从 v1.4.4 起,
不带参数或传入 undefined、null、Bun.file() 文件或 S3 文件时,Bun.hash() 会抛出 TypeError,而不再对 ""、"undefined"、"null" 或空内容进行哈希——请先读取文件
(await file.bytes())。
参考:有关所有哈希算法、CryptoHasher 流式 API,以及密码哈希选项(bcrypt 与 argon2id、成本参数),请参阅
references/hashing.md。
压缩
// Gzip
const compressed = Bun.gzipSync(data) // Uint8Array → Uint8Array
const decompressed = Bun.gunzipSync(compressed)
// Deflate
const compressed = Bun.deflateSync(data)
const decompressed = Bun.inflateSync(compressed)
// Zstandard (zstd)
const compressed = Bun.zstdCompressSync(data)
const decompressed = Bun.zstdDecompressSync(compressed)
// With options
Bun.gzipSync(data, { level: 9, memLevel: 9 })
Bun.deflateSync(data, { level: 6 })
Bun.zstdCompressSync(data, { level: 3 })
所有压缩函数都接受 Uint8Array | string | ArrayBuffer,并返回 Uint8Array。
memLevel 和 strategy 从 v1.4.4 起生效,超出范围的值(memLevel 不在
1-9 范围内,strategy 不在 0-4 范围内)会抛出 RangeError;v1.4.3 会忽略两者并使用
默认值进行压缩。
对于流,CompressionStream 从 v1.4.3 起接受 level——否则 brotli 会以
质量级别 11 运行,对于大型动态响应来说速度很慢。取值范围:gzip / deflate /
deflate-raw 为 0-9,brotli 为 0-11,zstd 为 1-22;超出范围会抛出 RangeError。Bun 1.4.2
接受此选项但会忽略它。
// Inside a Bun.serve handler
const body = Bun.file('big.json').stream().pipeThrough(new CompressionStream('brotli', { level: 4 }))
return new Response(body, { headers: { 'Content-Encoding': 'br' } })
实用工具
// Which (find binary in PATH)
Bun.which('node') // '/usr/local/bin/node' or null
Bun.which('bun', { PATH: '/custom/bin' })
// Inspect (like console.log formatting)
Bun.inspect(obj) // string
Bun.inspect(obj, { depth: 4, colors: true })
// Module resolution
Bun.resolveSync('./module', '/from/dir') // Resolved absolute path
// Deep equality
Bun.deepEquals(a, b) // boolean (structural equality)
Bun.deepEquals(a, b, true) // Strict (differentiates 0 and -0)
// Sleep
await Bun.sleep(1000) // ms
await Bun.sleep(Bun.nanoseconds() + 1e9) // Until timestamp
// Timing
Bun.nanoseconds() // High-resolution timer (bigint)
// UUID
Bun.randomUUIDv7() // Time-ordered UUID v7
// String width (for terminal column alignment)
Bun.stringWidth('hello') // 5
Bun.stringWidth('你好') // 4 (CJK double-width)
// Peek at a promise without awaiting
const value = Bun.peek(promise) // Returns value if resolved, promise if pending
// Color detection
Bun.color('red', 'css') // 'rgb(255, 0, 0)'
Bun.color('#ff0000', 'ansi') // ANSI escape code
Bun.color('hsl(0, 100%, 50%)', 'number') // 0xff0000
参考:完整的实用工具函数签名和示例,请参阅
references/utilities.md。
Semver(Bun.semver)
内置 semver 操作——可替代 semver npm 包。
// Check if a version satisfies a range
Bun.semver.satisfies('1.2.3', '^1.0.0') // true
Bun.semver.satisfies('2.0.0', '>=1.0 <2.0') // false
Bun.semver.satisfies('1.0.0-beta', '*') // false (pre-release excluded by default)
// Sort versions (returns -1, 0, or 1)
Bun.semver.order('1.0.0', '2.0.0') // -1 (a < b)
Bun.semver.order('2.0.0', '1.0.0') // 1 (a > b)
Bun.semver.order('1.0.0', '1.0.0') // 0 (equal)
// Sort an array of versions
const versions = ['3.0.0', '1.2.0', '2.1.0']
versions.sort(Bun.semver.order) // ['1.2.0', '2.1.0', '3.0.0']
序列化(bun:jsc)
用于高效序列化的二进制结构化克隆。
import { serialize, deserialize } from 'bun:jsc'
const data = { key: 'value', nested: [1, 2, 3] }
const bytes = serialize(data) // Uint8Array
const restored = deserialize(bytes) // Original structure
处理复杂对象时,比 JSON.stringify/JSON.parse 更快。支持 JSON 不支持的类型:Date、RegExp、Map、Set、ArrayBuffer 等。
图像处理(Bun.Image)
内置图像解码/转换/编码(v1.3.14+)——可替代 sharp 和 jimp。
const thumb = await Bun.file('upload.jpg')
.image()
.resize(400, 400, { fit: 'cover' })
.rotate(90).flip().flop()
.modulate({ brightness: 1.1 })
.webp({ quality: 82 })
.bytes()
await Bun.file('hero.jpg').image().resize(1024).webp().write('thumb.webp')
const { width, height, format } = await new Bun.Image(buffer).metadata()
const blur = await Bun.file('hero.jpg').image().placeholder() // thumbhash data URL
const pasted = Bun.Image.fromClipboard() // v1.4+, macOS/Windows only, null on Linux
格式支持因平台而异——请勿假定各平台支持情况一致:
| Linux | macOS | Windows | |
|---|---|---|---|
| JPEG、PNG、WebP | 是 | 是 | 是 |
| GIF、BMP(仅解码) | 内置 | ImageIO | WIC |
| HEIC / AVIF | ERR_IMAGE_FORMAT_UNSUPPORTED | ImageIO(AVIF 编码需要 Apple Silicon M3+) | WIC + Microsoft Store 编解码器(HEIF Image Extensions / AV1 Video Extension) |
| TIFF 解码 | 不支持 | ImageIO | WIC |
| 剪贴板 | 返回 null | 是 | 是 |
JPEG/PNG/WebP 使用静态链接的编解码器,因此它们的编码输出在各平台上字节完全一致;HEIC/AVIF/TIFF(以及 macOS/Windows 上的 GIF/BMP)则通过操作系统后端处理。没有 .gif()/.bmp()/.tiff() 编码方法——请将这些格式解码后的图像重新编码为
JPEG/PNG/WebP。CMYK 和 YCCK JPEG(来自 Photoshop 和印刷版 PDF 的印刷用途导出文件)
从 v1.4.2 起可以解码,并会转换为 RGB,因此平台支持的所有转换和编码器都能处理这些图像;v1.4.1 及更早版本会以 Image: decode failed 拒绝它们。从 v1.4.3 起,轻微损坏的 JPEG(含有多余字节、缺少结束标记、扫描数据被截断)也可以解码,缺失的区块会显示为纯灰色;而 v1.4.2 会以 ERR_IMAGE_DECODE_FAILED 拒绝此类图像。
参考:请参阅
references/image.md和node_modules/bun-types/docs/runtime/image.mdx,查看完整的兼容性矩阵。
浏览器自动化(Bun.WebView)
无头浏览器自动化(v1.3.12+)——无需 Playwright 或 Puppeteer,即可导航、点击、输入、滚动、运行 JS 和 截屏(macOS 上使用系统 WebKit,或在 macOS、Linux 和 Windows 上使用已安装的 Chrome/Chromium/Edge)。点击和滚动都是真实的用户输入。
await using view = new Bun.WebView({ width: 1280, height: 720 })
await view.navigate('https://bun.sh')
await view.click("a[href='/docs']")
const title = await view.evaluate('document.title')
await Bun.write('page.png', await view.screenshot()) // returns a Blob
await view.cdp('Page.captureScreenshot', {}) // raw CDP escape hatch
参考:请参阅
references/webview.md和node_modules/bun-types/docs/runtime/webview.mdx,了解输入模拟和 CDP 事件。
Bun 1.4.x 新增功能
精简索引——任务适用时可先从这里入手,随后阅读链接文档再编写代码。 未标注的条目在 1.4.0 中发布。
| API | 用途 | 文档(node_modules/bun-types/docs/) |
|---|---|---|
Bun.XML.parse() / .stringify() | 无需 fast-xml-parser/xml2js 即可处理 XML;.xml 导入会返回解析后的文档 | runtime/xml.mdx |
Bun.TOML.stringify() | 编写 TOML(解析器现已符合 TOML v1.1.0) | runtime/toml.mdx |
Bun.secrets | 将凭据存储在操作系统钥匙串中,而非点文件中(实验性功能) | runtime/secrets.mdx |
Bun.spawn({ cgroup }) | 在 Linux 上,子进程启动前限制其内存和 PID 数量 | runtime/child-process.mdx |
Bun.Image.fromClipboard() | 从系统剪贴板读取图像(macOS/Windows) | runtime/image.mdx |
res.textStream() / req.textStream() | 将请求体迭代为已解码的 UTF-8 字符串,而非字节 | 无对应文档页面——参见 bun-types/fetch.d.ts |
fetch(url, { compress: 'gzip' }) | 压缩请求体并设置 Content-Encoding | runtime/networking/fetch.mdx |
routes: { '/x/*': { dir: './public' } } | 提供目录服务;可替代 express.static/sirv | runtime/http/routing.mdx |
process.on('memoryPressure', fn) | 操作系统报告内存不足时清理缓存;监听器会收到 'warning' 或 'critical' | 无对应文档页面——参见 bun-types/overrides.d.ts |
Bun.isStandaloneExecutable | 在 --compile 二进制文件中进行分支判断,且不分配内存 | bundler/executables.mdx |
| ML-DSA / ML-KEM | 后量子签名和密钥封装 | runtime/nodejs-compat.mdx |
Bun.serve({ http2: true })(v1.4.1+) | 在同一端口上提供 HTTP/2 和 HTTP/1.1;仅使用 HTTP/2 时设置 http1: false | runtime/http/server.mdx |
Bun.write(path, response) 流(v1.4.1+) | 下载到磁盘,无需缓冲请求体 | runtime/file-io.mdx |
WebSocket#pause() / resume() / isPaused(v1.4.1+) | 在客户端向对端实施背压(Bun 扩展) | 无对应文档页面——参见 bun-types/bun.d.ts |
crypto.argon2Sync() / 回调式 argon2()(v1.4.1+) | 原始 Argon2 标签,与 Node 逐字节一致;PHC 字符串使用 Bun.password | runtime/nodejs-compat.mdx |
fetch(url, { unix }) keep-alive(v1.4.1+) | 复用 Unix 套接字连接;支持 tls: { ca } | runtime/networking/fetch.mdx |
ServerWebSocket 上的 binaryType: "blob"(v1.4.1+) | 像客户端一样,以 Blob 接收二进制帧 | runtime/http/websockets.mdx |
import x from "./f" with { type: "text" } 类型支持(v1.4.1+) | TypeScript 7.1+ 中由加载器确定类型的导入(text、file、md、markdown、toml、yaml、jsonc、json5、xml、sqlite、html) | bun-types/ts7.1/import-attributes.d.ts |
Bun.FetchSession(v1.4.3+) | 为每个客户端单独设置 TLS、代理和 keep-alive,并使用私有连接池;可替代 undici 的 Agent / dispatcher | runtime/networking/fetch.mdx |
fetch(url, { proxy: false })、respectNoProxy(v1.4.3+) | 对单个请求跳过代理环境设置,或对显式代理忽略 NO_PROXY | runtime/networking/fetch.mdx |
Bun.ModuleGraph(v1.4.3+,实验性功能) | 在一个进程中运行同一应用的多个实例,每个实例都有全新的模块状态及独立的计时器和 I/O;这不是沙箱 | runtime/module-graph.mdx |
--disallow-code-generation-from-strings[=strict](v1.4.3+) | 让 eval() / new Function() 抛出 EvalError;启用 =strict 后,node:vm 和 data: 导入也会抛出 | runtime/code-generation-from-strings.mdx |
new CompressionStream(format, { level })(v1.4.3+) | 在流式请求体上权衡压缩比与速度 | 无对应文档页面——参见 bun-types/globals.d.ts |
Bun.serve 中的 If-Range(v1.4.3+) | 支持断点续传;文件变更时会重新完整下载 | runtime/http/routing.mdx |
Bun.secrets.set({ persist: "local" })(v1.4.3+) | 将 Windows 凭据保留在本机,而不随账户漫游 | runtime/secrets.mdx |
Bun.unsafe.setJITPolicy()(v1.4.3+) | --compile-jit-policy 可执行文件进入交互模式后,恢复常规 JIT | bundler/executables.mdx |
db.function() / db.aggregate()(v1.4.4+) | 在 bun:sqlite 中使用 JavaScript 编写 SQL 函数、聚合函数和窗口函数 | runtime/sqlite.mdx |
db.onInsert / onUpdate / onDelete(v1.4.4+) | 对此 Database 写入的每一行作出响应(钩子内不能执行查询) | runtime/sqlite.mdx |
new SQL({ transform: SQL.camel })(v1.4.4+) | 在任意适配器中,双向将 first_name 列转换为 firstName;另有 SQL.pascal、SQL.kebab | runtime/sql.mdx |
sql.json(value)(v1.4.4+) | 将数字、字符串、布尔值或 JSON null 存储为 JSON | runtime/sql.mdx |
query.cancel()(v1.4.4+,现已可用) | 停止正在运行的 PostgreSQL 查询;此方法此前虽已存在,但不起作用 | runtime/sql.mdx |
query.writable() / query.readable()(v1.4.4+) | 通过 Web 流使用 PostgreSQL COPY ... FROM STDIN / TO STDOUT | runtime/sql.mdx |
result.columns / result.statement(v1.4.4+) | 获取 PostgreSQL 和 MySQL 的列类型及语句文本 | runtime/sql.mdx |
ServerWebSocket#pause() / resume() / isPaused(v1.4.4+) | 针对发送过快的客户端,在服务端实施背压 | runtime/http/websockets.mdx |
websocket.error(error, ws)(v1.4.4+) | 关闭处理器抛出异常的套接字 | runtime/http/websockets.mdx |
new WebSocket(url, { proxy: { url, tls } })(v1.4.4+) | 为 HTTPS 代理和服务器分别设置 TLS 选项 | 无对应文档页面——参见 bun-types/bun.d.ts |
ws 中的 createWebSocketStream()(v1.4.4+) | 在 ws 套接字上创建 Node Duplex;此前会抛出 “Not supported yet in Bun” | npm ws 文档 |
Bun.Glob 的 extglob 和 {1..3}(v1.4.4+) | !(*.test).ts、@(app|lib)、编号分片——workspaces 和 --filter 中也支持 | runtime/glob.mdx |
ReadableStream、WritableStream 和 TransformStream 自 1.4 起已成为原生功能,并会自动应用背压——当套接字无法接收更多数据时,Bun.serve 会暂停请求/响应正文;当没有任何内容在消费正文时,fetch() 会暂停套接字。过去需要缓冲整个负载的流式代码不再需要手动实现节流,前提是管道中的每个阶段都遵循背压。 |
参考:有关 1.4 至 1.4.4 中已更改的行为,请参阅
references/migration-1.4.md(针对 URL 主机名的 TLS 验证、localhost环回解析、wsArrayBuffer帧、.json()错误消息、每个请求级checkServerIdentity对应一个 TLS 连接、未处理的fetch()拒绝、WebSocket 关闭代码、glob 语法、bun:sqlite错误处理,以及每个补丁修复的回归问题)——这是 Bun 已发布文档未涵盖的内容,因为文档只描述当前状态。
脚本模式
CLI 脚本模板
#!/usr/bin/env bun
const args = Bun.argv.slice(2)
const command = args[0]
switch (command) {
case 'generate':
await generate(args.slice(1))
break
case 'process':
await process(args.slice(1))
break
default:
console.log('Usage: script <generate|process> [args]')
process.exit(1)
}
文件生成器
const glob = new Bun.Glob('**/*.schema.json')
for await (const path of glob.scan('./schemas')) {
const schema = await Bun.file(`./schemas/${path}`).json()
const code = generateTypeScript(schema)
const outPath = path.replace('.schema.json', '.ts')
await Bun.write(`./generated/${outPath}`, code)
}
数据管道
import { $ } from 'bun'
import { Database } from 'bun:sqlite'
// Fetch data
const data = await $`curl -s https://api.example.com/data`.json()
// Process and store
const db = new Database('output.sqlite')
db.exec('CREATE TABLE IF NOT EXISTS items (id TEXT PRIMARY KEY, value TEXT)')
const insert = db.prepare('INSERT OR REPLACE INTO items (id, value) VALUES (?, ?)')
const batch = db.transaction((items) => {
for (const item of items) {
insert.run(item.id, JSON.stringify(item))
}
})
batch(data.items)
db.close()
最佳实践
- 优先使用
Bun.file()+Bun.write(),而不是fs.readFile/fs.writeFile - 使用
Bun.$执行 shell 命令,而不是child_process - 当
DATABASE_URL可用时,使用Bun.sql()连接 PostgreSQL/MySQL——零依赖、连接池、标记模板 - 使用
bun:sqlite操作嵌入式/本地 SQLite 数据库,而不是外部包 - 使用
Bun.Glob,而不是globnpm 包 - 使用
Bun.CryptoHasher,而不是crypto.createHash - 使用
Bun.password,而不是bcrypt/argon2npm 包 - 使用
Bun.gzipSync/Bun.zstdCompressSync,而不是zlib - 使用
Bun.env访问环境变量(与process.env相同,但带类型) - 使用
import.meta.dir,而不是__dirname(与 Node 兼容时可使用import.meta.dirname) - 使用
Bun.which(),而不是whichnpm 包 - 使用
Bun.s3执行 S3 操作,而不是@aws-sdk/client-s3 - 使用
Bun.redis,而不是ioredis或redisnpm 包 - 使用
Bun.Archive处理 tarball,而不是tar或archivernpm 包 - 使用
JSONC.parse(),而不是jsonc-parser包 - 使用
JSON5.parse(),而不是json5包 - 使用
JSONL.parse()解析 JSON Lines,而不是手动按换行符拆分 - 使用
markdown.html()/markdown.ansi(),而不是marked、remark或markdown-it包 - 使用
Bun.wrapAnsi(),而不是wrap-ansinpm 包 - 使用
Bun.sliceAnsi(),而不是slice-ansinpm 包 - 使用
Bun.Image处理图像,而不是sharp或jimp - 使用
Bun.XML,而不是fast-xml-parser或xml2js(v1.4+) - 使用
Bun.secrets,而不是将凭据写入点文件(v1.4+) - 使用
Bun.Terminal,而不是node-pty来创建伪终端 - 使用
URLPattern,而不是path-to-regexp - 使用
CompressionStream/DecompressionStream进行流式压缩——在热点路径上使用 brotli 时设置level(v1.4.3+) - 编写非简单的 Bun 代码前,先阅读
node_modules/bun-types/docs/**/*.mdx——按明确路径打开,绝不要编辑node_modules/下的任何内容 - 使用
Bun.FetchSession设置客户端专属的 TLS、代理或 keep-alive 配置,而不是使用undici的Agent/dispatcher,因为 Bun 的fetch()会忽略它们(v1.4.3+) - 依赖
bun-types(版本固定为bun --version),而不是滞后于每个版本发布的@types/bun——请参阅“先阅读 Bun 自带的文档” - 使用
db.function()/db.aggregate()执行 SQLite 应逐行运行的逻辑,而不是将行读出后在 JavaScript 中计算,再写回数据库(v1.4.4+) - 使用
transform: SQL.camel,而不是手动映射snake_case列(v1.4.4+) - 为每个
ws套接字添加'error'监听器——自 1.4.4 起,未处理的错误会导致进程崩溃,与 Node 一致;并且在调用server.upgrade()前检查Origin
参考资料
references/migration-1.4.md——1.3 到 1.4.4 之间的变更(不兼容行为)references/http-server.md——Bun.serve路由、TLS、WebSockets、静态文件references/file-io.md、references/shell-and-process.md、references/networking.mdreferences/sql-client.md、references/sqlite-and-data.md、references/redis-client.md、references/s3-client.mdreferences/utilities.md、references/hashing.md、references/image.md、references/webview.md