Claude CodeでBunランタイムを実務導入する手順
BunをClaude Codeで安全に導入する実装手順、テスト、落とし穴、移行判断を実例で解説。
Bunは「速いNode.js互換ランタイム」とだけ紹介されがちですが、実務で見るべき点は速度だけではありません。BunはJavaScript/TypeScriptを動かすランタイム、依存関係を入れるパッケージマネージャー、package.jsonのコマンドを動かすスクリプトランナー、テストを実行するテストランナー、そしてバンドラーを1つのCLIにまとめたツールです。
初心者向けに言い換えると、Bunは「アプリを動かす土台」と「開発中によく使う道具箱」が一体になったものです。Claude Codeと組み合わせると、既存のNode.jsプロジェクトをいきなり全部移行するのではなく、bun install、bun run、bun test、小さなBun.serve APIから段階的に試せます。
この記事では、Bunの公式ドキュメントで扱われているBun.serve、package scriptsを実行するbun run、Bun test runner、Node.js互換性を前提に、Claude Codeへどう依頼し、どこを人間がレビューするかを整理します。Bun全体の概要はBun公式ドキュメントも参照してください。
内部リンクとして、API設計はClaude Code API開発ガイド、テスト方針はClaude Codeテスト戦略、速度改善の考え方はClaude Codeパフォーマンス最適化と合わせて読むと実装判断がしやすくなります。
導入前に決めること
最初に決めるのは「Bunに全部置き換えるか」ではなく、「どこなら失敗しても戻せるか」です。Claude Codeには、次のように範囲を狭く指定します。
既存のNode.jsプロジェクトを一度に移行しない。まずBunで依存関係のインストール、package scripts、単体テスト、ローカルHTTP APIだけを検証する。変更点と戻し方を最後に表で出して。
用語もここでそろえておきます。
| 用語 | やさしい言い換え | レビューで見る点 |
|---|---|---|
| runtime | JavaScriptを実行する土台 | Node.js専用APIに依存していないか |
| package script | package.jsonに書くショートカットコマンド | bun runで同じ意味になるか |
| test runner | テストを探して実行する係 | Jest前提の機能を使いすぎていないか |
| Node compatibility | Node.js向けコードがどこまで動くか | 依存パッケージと組み込みAPIの差分 |
おすすめの導入順は、以下の4段階です。
| 段階 | 試すこと | 成功条件 |
|---|---|---|
| 1 | bun installで依存解決 | lockfile差分を説明できる |
| 2 | bun runで既存scriptsを実行 | dev、test、lintの意味が変わらない |
| 3 | bun testで小さな単体テスト | watchやmockの差分を把握する |
| 4 | Bun.serveで小さなHTTP API | production移行前の制約を明文化する |
概念図にすると、Bun導入は「置換」ではなく次の流れです。
| 現状把握 | 小さな検証 | 差分レビュー | チーム導入 |
|---|---|---|---|
| Node scripts、test、APIを棚卸し | Bunで同じ入口を作る | 互換性、速度、エラーを比較 | CLAUDE.mdとCIに反映 |
コピペで試せる最小プロジェクト
新しいディレクトリで試すなら、次のファイル構成にします。既存アプリでいきなり実行せず、まずは小さなPoCでBunの動きを確認してください。
mkdir bun-claude-lab
cd bun-claude-lab
bun init -y
package.jsonはBun専用にしすぎず、scriptsの意味が読み取れる名前にします。scriptsは「毎回長いコマンドを打たなくてよいようにした短縮名」です。
{
"name": "bun-claude-lab",
"type": "module",
"scripts": {
"dev": "bun --watch src/server.ts",
"start": "bun src/server.ts",
"test": "bun test",
"check": "bun test && bun run scripts/runtime-check.ts"
},
"dependencies": {},
"devDependencies": {}
}
次に、Bun公式ドキュメントで中心的に扱われているBun.serveでHTTPサーバーを作ります。Bun.serveは「Bunに組み込まれたHTTPサーバー起動API」です。Expressのような外部フレームワークを使わず、Requestを受け取りResponseを返します。
// src/server.ts
type ApiMessage = {
message: string;
receivedAt: string;
};
function json(data: unknown, status = 200): Response {
return Response.json(data, {
status,
headers: {
"Cache-Control": "no-store"
}
});
}
function notFound(pathname: string): Response {
return json({ error: "not_found", pathname }, 404);
}
const server = Bun.serve({
port: Number(process.env.PORT ?? 3000),
async fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/health") {
return json({ ok: true, runtime: "bun" });
}
if (url.pathname === "/api/echo" && req.method === "POST") {
const body = (await req.json().catch(() => null)) as { message?: string } | null;
if (!body?.message) {
return json({ error: "message is required" }, 400);
}
const payload: ApiMessage = {
message: body.message,
receivedAt: new Date().toISOString()
};
return json(payload, 201);
}
return notFound(url.pathname);
}
});
console.log(`Listening on ${server.url}`);
動作確認は次のコマンドです。
bun run dev
別のターミナルで確認します。
curl http://localhost:3000/health
curl -X POST http://localhost:3000/api/echo \
-H "Content-Type: application/json" \
-d '{"message":"hello from Bun"}'
Claude Codeへ頼むなら、実装だけでなく失敗時のレスポンスも指定します。
src/server.tsに/api/echoを追加して。正常系、JSON不正、message欠落、未定義ルートを分けて実装し、curlで確認するコマンドも出して。
Bun testで小さく固める
Bunにはbun:testがあり、Jestに似たAPIでテストを書けます。ただし、Jest完全互換と決めつけるのは危険です。公式ドキュメントでもJest互換を目指している一方、すべての機能が実装済みとは限らないため、既存テストのmock、snapshot、fake timerは移行前に確認します。
まずロジックを切り出します。
// src/message.ts
export function normalizeMessage(input: string): string {
return input.trim().replace(/\s+/g, " ");
}
export function createReply(input: string): { message: string; length: number } {
const message = normalizeMessage(input);
if (message.length === 0) {
throw new Error("message must not be empty");
}
return {
message,
length: message.length
};
}
テストはbun:testからdescribe、expect、testを読み込みます。
// src/message.test.ts
import { describe, expect, test } from "bun:test";
import { createReply, normalizeMessage } from "./message";
describe("message helpers", () => {
test("normalizes whitespace", () => {
expect(normalizeMessage(" hello bun ")).toBe("hello bun");
});
test("creates a reply payload", () => {
expect(createReply(" Claude Code ")).toEqual({
message: "Claude Code",
length: 11
});
});
test("rejects an empty message", () => {
expect(() => createReply(" ")).toThrow("message must not be empty");
});
});
実行します。
bun test
bun test --watch
Claude Codeには「テストを増やして」だけでは足りません。次のように観点を渡すと、差分がレビューしやすくなります。
src/message.tsの単体テストをBun testで追加して。正常系、空文字、余分な空白、将来APIレスポンスに使う戻り値の形を確認して。Jest固有APIが必要な場合は、Bun testで代替できるかコメントして。
package scriptsをBunに寄せる
bun runはpackage.jsonのscriptsを実行します。ここで注意したいのは、Bun本体のコマンド名とscript名が衝突することです。迷う場合は短縮形のbun devより、明示的にbun run devを使うほうがレビューしやすいです。
既存プロジェクトでは、いきなり全scriptを変えず、まずは対応表を作ります。
{
"scripts": {
"node:dev": "node --watch dist/server.js",
"node:test": "vitest run",
"bun:dev": "bun --watch src/server.ts",
"bun:test": "bun test",
"verify:bun": "bun run bun:test && bun run scripts/runtime-check.ts"
}
}
互換性確認用の小さなスクリプトも置けます。
// scripts/runtime-check.ts
import { existsSync } from "node:fs";
import { join } from "node:path";
const checks = [
["package.json exists", existsSync(join(process.cwd(), "package.json"))],
["Bun global is available", typeof Bun !== "undefined"],
["fetch is available", typeof fetch === "function"],
["Buffer is available", typeof Buffer !== "undefined"]
] as const;
for (const [label, ok] of checks) {
console.log(`${ok ? "PASS" : "FAIL"} ${label}`);
}
if (checks.some(([, ok]) => !ok)) {
process.exit(1);
}
実行します。
bun run verify:bun
この段階でClaude Codeに依頼したいのは、速度の宣伝文句ではなく差分の棚卸しです。
package.jsonのscriptsを読み、Bunで安全に試せるもの、Node.jsのまま残すもの、判断保留にするものを表にして。変更はまだしない。理由と確認コマンドも書いて。
具体的なユースケース
1つ目は、社内ツールや管理画面の小さなAPIです。Bun.serveだけで/health、簡単なJSON API、Webhook受信のPoCを作れます。Claude Codeにエラーレスポンス、curl、テストまで一緒に出させると、検証の抜けが減ります。
2つ目は、既存Node.jsプロジェクトの開発体験改善です。production runtimeはNode.jsのままでも、依存インストール、script実行、単体テストだけBunで試す選択肢があります。ここでは「全部移行」ではなく「開発ループを短くする」ことが目的です。
3つ目は、TypeScriptの学習用プロジェクトです。BunはTypeScriptファイルを直接実行できるため、初心者がtsc、tsx、node --loaderの違いで止まりにくくなります。ただし、型チェックそのものは別途tsc --noEmitを残す判断も必要です。
4つ目は、記事・教材・SaaSのデモサーバーです。ClaudeCodeLabのような技術メディアでは、コード例が実際に動くことが信頼につながります。Bunで軽いサンプルAPIを作り、記事内のcurlとテストをそろえると、読者が試しやすくなります。
失敗しやすい落とし穴
1つ目は、Node.js互換性を「完全に同じ」と思い込むことです。BunはNode.js互換を強く意識していますが、すべてのAPI、ネイティブアドオン、依存パッケージの挙動が同じとは限りません。特にnode:vm、ストリーミング、古いCommonJS前提のパッケージ、postinstallに依存するパッケージは確認します。
2つ目は、Jest前提のテストをそのままbun testへ移すことです。基本的なexpectやdescribeは近い書き味ですが、mockやsnapshot、DOM周りは差分が出やすい領域です。テスト移行では、失敗したテストを「Bunの問題」と決めつけず、テストがJest固有機能に依存していないか見ます。
3つ目は、scriptの意味が変わることです。bun runのフラグ位置、Bun内蔵コマンドとの名前衝突、Windowsでのshell挙動など、開発者ごとの環境差が出ます。チームで使うなら、READMEやCLAUDE.mdに「使うコマンド」と「使わない短縮形」を書いておきます。
4つ目は、速さだけで採用を決めることです。インストールや起動が速くても、CI、Docker、デプロイ先、監視、障害時の切り戻しが未整理なら、production移行は早すぎます。最初はlocal devやtest runnerから入るほうが安全です。
5つ目は、Claude Codeに移行作業を丸投げすることです。Claude Codeは差分の作成には強い一方、実行環境の暗黙知、CIの秘密情報、運用上の優先順位までは自動では理解しません。必ず「変更してよい範囲」「戻し方」「確認コマンド」「触らないファイル」を指定します。
Claude Codeへの実務プロンプト
次のプロンプトは、既存リポジトリの初回調査に使えます。
このリポジトリでBunを段階導入できるか調べて。まずファイル変更はしない。
package.json、lockfile、test runner、Node.js組み込みAPI、CI設定、Dockerfileを読み、Bunに置き換えやすい箇所と危険な箇所を表にして。最後に、最小PoCの変更案を3つ出して。
小さな実装まで依頼するなら、範囲をさらに狭めます。
src/server.tsだけを追加して、Bun.serveの/healthと/api/echoを実装して。package.jsonにはbun:devとbun:testだけ追加。既存のNode.js scriptsは変更しない。Bun未導入の環境でも戻せるように、確認コマンドと戻し方を最後に書いて。
レビュー依頼は次の形が実用的です。
Bun導入差分をレビューして。Node.js互換性、package scriptsの意味の変化、test runnerの差分、production deployに持ち込むリスク、ドキュメント不足を優先して指摘して。速度改善の話は、実測値がある場合だけ触れて。
チーム導入と収益導線
Bun導入は、単なる技術選定ではなく、チームの開発ループを短くする投資です。記事、教材、社内テンプレート、SaaSのデモ環境で使うなら、CLAUDE.mdに「Bunで実行してよいコマンド」「Node.jsのまま残すコマンド」「CIで必ず確認するコマンド」を書くと運用が安定します。
個人で基本コマンドを覚える段階なら、まず無料チートシートでClaude Codeの確認手順を固定してください。Bun移行を含むCLAUDE.md、hooks、権限、レビュー観点までまとめて整えるなら教材・テンプレート一覧が使えます。チームのNode.js資産をBunへ段階移行する判断、CI/CD、レビュー規約、ロールバックまで一緒に設計したい場合はClaude Code研修・導入相談で実リポジトリ前提に整理できます。
この記事で紹介した内容を試した結果
この記事のサンプルは、Bun公式ドキュメントのBun.serve、bun run、bun test、Node.js互換性ページの考え方に合わせて、ローカルPoCとしてコピーしやすい最小構成にしました。執筆環境ではbunコマンドが未導入だったため実行まではできませんでしたが、読者が手元で検証する場合は、bun run dev、curl /health、curl /api/echo、bun test、bun run verify:bunの順に確認すれば、HTTP API、package scripts、テスト、互換性の最初の差分を切り分けられます。公開前レビューでは、コード例の構文、公式リンク、内部リンク、CTA、updatedDate、heroImageがそろっていることを確認してください。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
ObsidianメモをCLAUDE.mdに変えるClaude Code運用: 文脈を毎回説明しない仕組み
Obsidianの作業メモからCLAUDE.md用の運用ノートを作り、Claude Codeに安定した文脈を渡す方法。
Claude Code Revenue CTA Routing: 記事からPDF、Gumroad、相談へ送る設計
PVだけで終わらせず、読者の状態に合わせて無料PDF、Gumroad教材、導入相談へ分岐するCTA設計です。
Claude Codeチーム引き継ぎルール: レビュー、権限、収益導線まで渡す実務手順
Claude Codeの作業をチームで渡すための証拠、権限、ロールバック、無料PDF/Gumroad/相談導線の実務ルール。