bun-api について
bun-apiは、Bunプロジェクトに取り組む開発者やコーディングエージェント向けのスキルです。BunネイティブAPI、バージョンごとの挙動、複雑なコードを書く前に同梱ドキュメントを参照する方法を説明します。
主な機能
- 01BunネイティブAPIのガイド
- 02Bun 1.4.xのバージョン案内
- 03同梱APIドキュメントへの案内
- 04ランタイム固有の移行上の注意
- 05スクリプトやサービスのタスク案内
活用シーン
- 01プロジェクトのスクリプトで使うBun APIの選定
- 02Bunのパッチ間での挙動確認
- 03bun-types内のAPIリファレンス検索
- 04HTTP、ネットワーク、データベースコードの実装
インストール
コマンドをコピーしてターミナルで実行します。
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 Runtime API
Bun は TypeScript をネイティブに実行します。tsc によるコンパイルも、ts-node も、ビルド手順も不要です。bun file.ts で任意の .ts ファイルを直接実行できます。実行時に型チェックは行われないため、型チェックには bun check(v1.4.3 以降。詳しくは bun-cli スキルを参照)を使用してください。Node.js の同等機能ではなく、Bun のネイティブ API を使用してください。より高速で使いやすく、追加の依存関係も不要です。
重要:Bun プロジェクト(bun.lock、bun.lockb、bunfig.toml のいずれかがある、または devDependencies に bun-types/@types/bun が含まれるプロジェクト)では、スクリプトの実行には必ず Bun を使用してください(node file.ts ではなく bun file.ts)。また、Node.js の同等機能よりも Bun のネイティブ 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 ストリーム | 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 ソケットのキープアライブ | fetch() が Host ヘッダーではなく URL のホストに対して TLS を検証する、localhost がシステムリゾルバーを介さずに解決される | アップグレード先としては選ばないでください。AsyncLocalStorage の値が漏洩し、ワーカーの '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 によりリクエストごとに接続が必要になる、未 await の拒否された fetch() によりプロセスが 1 で終了する、ALL_PROXY とより広い NO_PROXY 構文が適用される、コード生成フラグが強制される、sql.begin() がロールバック済みのトランザクションを拒否する | クライアントごとの TLS/プロキシ設定が必要な場合、または 1.4.1 時代のバグ(promisify(setTimeout)、キープアライブ時の 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 イベント、*(...)/{1..3} の glob での意味、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 の選び方を説明します。付属のドキュメントでは、正確なシグネチャとオプションを確認できます。
-
@types/bunではなくbun-typesを使用してください。bun-typesはすべての Bun リリースに含まれており、ドキュメントと型の両方を提供します。@types/bunは各リリースより遅れて更新され、多くの場合、1 日以上の遅れがあります。それにもかかわらず、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 |
| シェル、サブプロセス、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 |
使用する場面
- ファイルの生成、データの解析、マイグレーションの実行などのスクリプト
- ファイル処理と変換のパイプライン
- シェルスクリプトと自動化
- SQLite(
bun:sqlite)を使ったデータベース操作 - 接続 URL を使ったデータベースクエリ — プロジェクトの
.envまたは環境変数にDATABASE_URLがある場合(PostgreSQL、MySQL、Bun.sql()を使った SQLite) - S3 ストレージ操作 — プロジェクトに
AWS_ACCESS_KEY_IDがある場合、または S3 互換ストレージ(Bun.s3)を使用する場合 - Redis/Valkey のキャッシュと Pub/Sub — プロジェクトに
REDIS_URLまたはVALKEY_URLがある場合(Bun.redis) - Bun プロジェクトで行うあらゆるスクリプト作業
HTTP サーバー(Bun.serve)
組み込みの HTTP サーバーです。Express、Fastify、http.createServer を置き換えます。
手作業で URL を解析するよりも routes を使用してください。パラメーター、メソッドごとのハンドラー、アロケーションのない静的レスポンスを利用できます。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(Request に params と cookies を加えたもの)が渡されます。
主なメソッド: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()(WebSocket)とレスポンストレーラーは 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 を無視し、常に範囲を送信していました。
WebSocket(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() を呼び出すと、終了までにもう 1 回のラウンドトリップが必要です。リリースノートによると、サーバーが応答しない場合は 30 秒後に 1006 が返されます(BUN_CONFIG_WS_CLOSE_TIMEOUT。ws.terminate() は即座に接続を閉じます)。接続に失敗すると、error(event.error.code に ECONNREFUSED などが設定されます)が発火し、その後 1006 と空の reason を伴って close が発火します。組み込みの ws パッケージは、npm の Node 用 ws と同じ動作になりました。'error' には .code を持つ Error が渡され、'close' には Buffer の reason が渡されます。リスナーのない '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、プロキシ、キープアライブ設定と、プライベートな接続プールを持たせることができます。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 では接続が再利用されていました)。セッションでは接続ごとに 1 回実行され、その接続はプールされます。 session.fetchにpreconnectはありません。オプションの型がtypeof fetchの場合は、session.fetch as typeof fetchを渡してください。
プロキシの選択。 proxy: false を指定すると、HTTP_PROXY / HTTPS_PROXY / ALL_PROXY の設定にかかわらず直接接続します。スキーム固有の変数が未設定の場合に 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 で reject されます。1.4.2 では、プロキシの応答をオリジンからの応答として扱い、resolve していました。
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')
標準入出力
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 インターフェイス、write のオーバーロード、ストリーミング、MIME 検出、ファイル監視については、
references/file-io.mdを参照してください。
シェルとプロセスの実行
Bun.$(タグ付きテンプレートシェル)
シェルコマンドを実行する主な方法です。出力を含む 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 構文。 ?(...)、*(...)、+(...)、@(...)、!(...) は extglob 演算子で、{1..3} は範囲です。これは Bun が glob を使うすべての場所、つまり Bun.Glob、--filter、package.json の workspaces、files、sideEffects に適用されます("workspaces": ["packages/!(internal)"] が動作します)。1.4.3 ではこれらは文字列どおりにマッチしていたため、*(1).txt は copy(1).txt にマッチしましたが、現在は「1 が 0 回以上続き、その後に .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
接続 URL を使ってデータベースをクエリする、組み込みの SQL クライアントです。依存関係は不要で、タグ付きテンプレートリテラル、自動プリペアドステートメント、コネクションプールに対応しています。プロジェクトの .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 設定文も含め、行を返すものと判断した最初の文の後で停止していました)。affectedRows は SQLite と PostgreSQL で設定されます(常に null でした)。クエリが送信前にキャンセルされると、ERR_SQLITE_QUERY_CANCELLED/ERR_POSTGRES_QUERY_CANCELLED/ERR_MYSQL_QUERY_CANCELLED で reject されます(1.4.3 では処理が完了しませんでした)。また、SQLite では 2 回目の sql.begin() は cannot start a transaction within a transaction で失敗せず、待機します。PostgreSQL と MySQL の固有機能(配列バインディング、COPY、サーバー側キャンセル、channelBinding、bun --hot 実行時の接続再利用)はリリースノートに記載されています。確認に利用できるデータベースサーバーはありませんでした。
リファレンス:接続オプション、プール管理、セーブポイント、MySQL 固有機能、プリペアドステートメントの設定、変換、結果メタデータ、
COPY、キャンセルについては、references/sql-client.mdを参照してください。
S3 クライアント(Bun.s3)
Web 標準の Blob API を備えた組み込みの S3 クライアントです。依存関係は不要で、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、署名付き URL のオプション、マルチパートアップロード、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")
リファレンス:すべてのコマンド(文字列、ハッシュ、リスト、セット、ソート済みセット)、pub/sub、パイプライン、一般的なパターンについては、
references/redis-client.mdを参照してください。
アーカイブ(Bun.Archive)
オプションの gzip 圧縮を使って tarball を作成・展開します。
// 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) は例外になります。Map<string, File> を得るには await archive.files() を、展開するには 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) には OS レベルのジョブの文字列タイトルを渡します。ジョブハンドルは受け付けません。
プロセス内のジョブは 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 とユーティリティ 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 }は読み書きモードで開くのではなく、エラーをスローします。db.transaction(fn)は、fnがすでに拒否された Promise を返すとロールバックします。 最初の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 で確認済み。@types/bun
では 1.4.4 まで number | bigint と型付けされていました)、Bun.hash(key) % 16 は TypeError をスローします。v1.4.4 以降、
引数なし、undefined、null、または Bun.file()/S3 ファイルを指定した Bun.hash() は、""、"undefined"、"null"、または何もない値をハッシュ化する代わりに TypeError をスローします。先にファイルを読み取ってください
(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 がスローされます。1.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 操作機能です。npm パッケージ semver を置き換えます。
// 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 より高速です。Date、RegExp、Map、Set、ArrayBuffer など、JSON ではサポートされない型にも対応しています。
画像処理(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)は OS のバックエンドを経由します。.gif()/.bmp()/.tiff() のエンコーダーメソッドはありません。これらをデコードした画像は、JPEG/PNG/WebP として再エンコードしてください。CMYK および YCCK の JPEG(Photoshop や印刷用 PDF から書き出された印刷向け画像)は v1.4.2 以降でデコードでき、RGB に変換されるため、プラットフォームがサポートするすべての変換とエンコーダーを利用できます。1.4.1 以前では Image: decode failed で拒否されていました。v1.4.3 以降では、わずかに破損した JPEG(余分なバイト、終端マーカーの欠落、スキャンデータの切り詰め)もデコードでき、欠落ブロックは平坦なグレーで表示されます。1.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
リファレンス:入力シミュレーションと CDP イベントについては、
references/webview.mdおよびnode_modules/bun-types/docs/runtime/webview.mdxを参照してください。
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 | ドットファイルではなく OS のキーチェーンに認証情報を保存します(実験的) | 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) | OS からメモリ不足が報告されたときにキャッシュを破棄します。リスナーには '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+) | 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+) | Node とバイト単位で一致する生の Argon2 タグを生成します。PHC 文字列には Bun.password を使用します | runtime/nodejs-compat.mdx |
fetch(url, { unix }) のキープアライブ (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、プロキシ、キープアライブ設定を行います。undici の Agent/dispatcher の代わりになります | runtime/networking/fetch.mdx |
fetch(url, { proxy: false })、respectNoProxy (v1.4.3+) | 1 つのリクエストでプロキシ環境変数を無視するか、明示的なプロキシに対して NO_PROXY を無視します | runtime/networking/fetch.mdx |
Bun.ModuleGraph (v1.4.3+、実験的) | 1 つのプロセスで同じアプリのインスタンスを複数実行し、それぞれに新しいモジュール状態、独自のタイマーと 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+) | PostgreSQL の COPY ... FROM STDIN/TO STDOUT を Web ストリームとして扱います | 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で変更された動作(URLホスト名に対するTLS検証、
localhostのループバック解決、wsのArrayBufferフレーム、.json()のエラーメッセージ、リクエスト単位のcheckServerIdentityによるTLS接続、未処理のfetch()の拒否、WebSocketのクローズコード、glob構文、bun:sqliteのエラー処理、および各パッチで修正されたリグレッション)については、references/migration-1.4.mdを参照してください。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()
ベストプラクティス
fs.readFile/fs.writeFileよりもBun.file()+Bun.write()を優先してくださいchild_processの代わりに、シェルコマンドにはBun.$を使ってくださいDATABASE_URLが利用可能な場合は、PostgreSQL/MySQLにBun.sql()を使ってください。依存関係が不要で、コネクションプーリングとタグ付きテンプレートを利用できます- 外部パッケージの代わりに、組み込み/ローカルSQLiteデータベースには
bun:sqliteを使ってください globnpmパッケージの代わりに、Bun.Globを使ってくださいcrypto.createHashの代わりに、Bun.CryptoHasherを使ってくださいbcrypt/argon2npmパッケージの代わりに、Bun.passwordを使ってくださいzlibの代わりに、Bun.gzipSync/Bun.zstdCompressSyncを使ってください- 環境変数には
Bun.envを使ってください(process.envと同じですが、型が付いています) __dirnameの代わりにimport.meta.dirを使ってください(Node互換性にはimport.meta.dirnameを使ってください)whichnpmパッケージの代わりに、Bun.which()を使ってください- S3操作には
@aws-sdk/client-s3の代わりに、Bun.s3を使ってください ioredisまたはredisnpmパッケージの代わりに、Bun.redisを使ってください- tarballには
tarまたはarchivernpmパッケージの代わりに、Bun.Archiveを使ってください jsonc-parserパッケージの代わりに、JSONC.parse()を使ってくださいjson5パッケージの代わりに、JSON5.parse()を使ってください- JSON Linesを手動で改行分割する代わりに、
JSONL.parse()を使ってください marked、remark、markdown-itパッケージの代わりに、markdown.html()/markdown.ansi()を使ってくださいwrap-ansinpmパッケージの代わりに、Bun.wrapAnsi()を使ってくださいslice-ansinpmパッケージの代わりに、Bun.sliceAnsi()を使ってください- 画像処理には
sharpまたはjimpの代わりに、Bun.Imageを使ってください fast-xml-parserまたはxml2jsの代わりに、Bun.XMLを使ってください(v1.4+)- 認証情報をドットファイルに書き込む代わりに、
Bun.secretsを使ってください(v1.4+) - 擬似端末には
node-ptyの代わりに、Bun.Terminalを使ってください path-to-regexpの代わりに、URLPatternを使ってください- ストリーミング圧縮には
CompressionStream/DecompressionStreamを使ってください。ホットパスでbrotliを使う場合は、levelを指定してください(v1.4.3+) - Bunのコードを本格的に書く前に、
node_modules/bun-types/docs/**/*.mdxを読み、明示的なパスで開いてください。node_modules/以下は編集しないでください undiciのAgent/dispatcherはBunのfetch()では無視されるため、クライアントごとのTLS、プロキシ、またはキープアライブ設定には、代わりにBun.FetchSessionを使ってください(v1.4.3+)- リリースごとに遅れる
@types/bunではなく、bun --versionに固定したbun-typesに依存してください。「まずBun独自のドキュメントを読む」を参照してください - SQLiteが行ごとに実行すべきロジックには、行を読み出してJavaScriptで計算し、書き戻すのではなく、
db.function()/db.aggregate()を使ってください(v1.4.4+) snake_caseの列を手動でマッピングする代わりに、transform: SQL.camelを使ってください(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、WebSocket、静的ファイル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