mcpField
B
bun-api

bun-api

github.com/dmythro开发7203 次安装4 天前更新
代码仓库

关于 bun-api

bun-api 是面向 Bun 项目开发者和编码 Agent 的技能,介绍 Bun 原生 API、版本相关行为,以及编写复杂代码前如何查阅 Bun 随附文档。

主要功能

  1. 01Bun 原生 API 使用指南
  2. 02Bun 1.4.x 版本说明
  3. 03随附 API 文档索引
  4. 04运行时相关迁移提示
  5. 05脚本与服务任务指南

适用场景

  1. 01为项目脚本选择 Bun API
  2. 02核对 Bun 补丁版本间的行为
  3. 03在 bun-types 中查找 API 参考
  4. 04编写 HTTP、网络或数据库代码

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dmythro/agent-skills --skill bun-api

安装后在 Claude Code 中输入/bun-api确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
file-io.md
hashing.md
http-server.md
image.md
migration-1.4.md
networking.md
redis-client.md
s3-client.md
shell-and-process.md
sql-client.md
sqlite-and-data.md
utilities.md
webview.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 StreamsBun.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-alivefetch() 根据 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; 随附文档则说明确切的签名和选项。

  1. 依赖 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
    
  2. 通过明确路径打开。 启用 Bun 的全局虚拟存储后,node_modules/bun-types 是一个符号链接:find node_modules -name '*.mdx' 和 rg <pattern> node_modules 不会返回 任何结果,而 find node_modules/bun-types/docs -name '*.mdx' 可以正常工作。

  3. 切勿编辑 node_modules/ 下的文件。 使用全局存储时,机器上的每个项目都共享同一个 inode—— 在其中写入会影响所有项目。请使用 bun patch。

  4. 未安装? 同一路径也可在线访问:docs/runtime/sql.mdx 对应 https://bun.com/docs/runtime/sql。

任务文档路径(位于 node_modules/bun-types/docs/ 下)
HTTP 服务、路由、WebSocketruntime/http/server.mdx、runtime/http/routing.mdx、runtime/http/websockets.mdx
fetch、TCP、UDP、DNSruntime/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、子进程、PTYruntime/shell.mdx、runtime/child-process.mdx
SQL、SQLite、Redis、S3runtime/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、CSRFruntime/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

格式支持因平台而异——请勿假定各平台支持情况一致:

LinuxmacOSWindows
JPEG、PNG、WebP是是是
GIF、BMP(仅解码)内置ImageIOWIC
HEIC / AVIFERR_IMAGE_FORMAT_UNSUPPORTEDImageIO(AVIF 编码需要 Apple Silicon M3+)WIC + Microsoft Store 编解码器(HEIF Image Extensions / AV1 Video Extension)
TIFF 解码不支持ImageIOWIC
剪贴板返回 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-Encodingruntime/networking/fetch.mdx
routes: { '/x/*': { dir: './public' } }提供目录服务;可替代 express.static/sirvruntime/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: falseruntime/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.passwordruntime/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 / dispatcherruntime/networking/fetch.mdx
fetch(url, { proxy: false })、respectNoProxy(v1.4.3+)对单个请求跳过代理环境设置,或对显式代理忽略 NO_PROXYruntime/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 可执行文件进入交互模式后,恢复常规 JITbundler/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.kebabruntime/sql.mdx
sql.json(value)(v1.4.4+)将数字、字符串、布尔值或 JSON null 存储为 JSONruntime/sql.mdx
query.cancel()(v1.4.4+,现已可用)停止正在运行的 PostgreSQL 查询;此方法此前虽已存在,但不起作用runtime/sql.mdx
query.writable() / query.readable()(v1.4.4+)通过 Web 流使用 PostgreSQL COPY ... FROM STDIN / TO STDOUTruntime/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 环回解析、ws ArrayBuffer 帧、.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()
最佳实践
  1. 优先使用 Bun.file() + Bun.write(),而不是 fs.readFile/fs.writeFile
  2. 使用 Bun.$ 执行 shell 命令,而不是 child_process
  3. 当 DATABASE_URL 可用时,使用 Bun.sql() 连接 PostgreSQL/MySQL——零依赖、连接池、标记模板
  4. 使用 bun:sqlite 操作嵌入式/本地 SQLite 数据库,而不是外部包
  5. 使用 Bun.Glob,而不是 glob npm 包
  6. 使用 Bun.CryptoHasher,而不是 crypto.createHash
  7. 使用 Bun.password,而不是 bcrypt/argon2 npm 包
  8. 使用 Bun.gzipSync/Bun.zstdCompressSync,而不是 zlib
  9. 使用 Bun.env 访问环境变量(与 process.env 相同,但带类型)
  10. 使用 import.meta.dir,而不是 __dirname(与 Node 兼容时可使用 import.meta.dirname)
  11. 使用 Bun.which(),而不是 which npm 包
  12. 使用 Bun.s3 执行 S3 操作,而不是 @aws-sdk/client-s3
  13. 使用 Bun.redis,而不是 ioredis 或 redis npm 包
  14. 使用 Bun.Archive 处理 tarball,而不是 tar 或 archiver npm 包
  15. 使用 JSONC.parse(),而不是 jsonc-parser 包
  16. 使用 JSON5.parse(),而不是 json5 包
  17. 使用 JSONL.parse() 解析 JSON Lines,而不是手动按换行符拆分
  18. 使用 markdown.html()/markdown.ansi(),而不是 marked、remark 或 markdown-it 包
  19. 使用 Bun.wrapAnsi(),而不是 wrap-ansi npm 包
  20. 使用 Bun.sliceAnsi(),而不是 slice-ansi npm 包
  21. 使用 Bun.Image 处理图像,而不是 sharp 或 jimp
  22. 使用 Bun.XML,而不是 fast-xml-parser 或 xml2js(v1.4+)
  23. 使用 Bun.secrets,而不是将凭据写入点文件(v1.4+)
  24. 使用 Bun.Terminal,而不是 node-pty 来创建伪终端
  25. 使用 URLPattern,而不是 path-to-regexp
  26. 使用 CompressionStream/DecompressionStream 进行流式压缩——在热点路径上使用 brotli 时设置 level(v1.4.3+)
  27. 编写非简单的 Bun 代码前,先阅读 node_modules/bun-types/docs/**/*.mdx——按明确路径打开,绝不要编辑 node_modules/ 下的任何内容
  28. 使用 Bun.FetchSession 设置客户端专属的 TLS、代理或 keep-alive 配置,而不是使用 undici 的 Agent/dispatcher,因为 Bun 的 fetch() 会忽略它们(v1.4.3+)
  29. 依赖 bun-types(版本固定为 bun --version),而不是滞后于每个版本发布的 @types/bun——请参阅“先阅读 Bun 自带的文档”
  30. 使用 db.function() / db.aggregate() 执行 SQLite 应逐行运行的逻辑,而不是将行读出后在 JavaScript 中计算,再写回数据库(v1.4.4+)
  31. 使用 transform: SQL.camel,而不是手动映射 snake_case 列(v1.4.4+)
  32. 为每个 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.md
  • references/sql-client.md、references/sqlite-and-data.md、references/redis-client.md、references/s3-client.md
  • references/utilities.md、references/hashing.md、references/image.md、references/webview.md

评论

支持 Markdown