【2025年最新】Bunで爆速JavaScript開発!従来の3倍速いランタイムの基本と活用法

Bunとは?JavaScriptランタイムの新たな選択肢
Bunとは、JavaScriptとTypeScriptを高速に実行するためのオールインワンツールキットです。JavaScript開発に必要なランタイム、バンドラー、テストランナー、パッケージマネージャを1つにまとめたツールで、2021年に登場して以来、Web開発者から大きな注目を集めています。
Bunの最大の特徴は、その圧倒的な実行速度です。Node.jsと比較して最大3倍の速度を実現し、開発者の生産性を大幅に向上させます。また、JavaScriptだけでなくTypeScriptもネイティブにサポートしているため、トランスパイル不要で直接実行できます。
# 基本的な使い方
bun run index.ts # TypeScriptファイルを直接実行
Bunはサーバーサイドのコードを書く際にも強力なサポートを提供し、特にAPIサーバーやマイクロサービスの構築に適しています。Node.jsと高い互換性を持ちながらも、よりモダンで効率的なAPIを提供している点が魅力です。
多くの一般的なNode.jsパッケージはBunでもそのまま動作するため、既存のプロジェクトからの移行も比較的容易です。ただし、あらゆるNode.jsモジュールとの完全な互換性はまだ実現されていないため、使用する際は互換性の確認が重要です。
「なぜもう一つのJavaScriptランタイムが必要なのか?」と疑問に思う方もいるでしょう。しかし、Bunは単なる代替ツールではなく、現代のWeb開発の課題を解決するために最初から設計されています。特に開発環境の起動時間の短縮、ビルドプロセスの高速化、APIレスポンスの改善などの点で大きなメリットをもたらします。
Nodeよりも速い!Bunが高性能な理由を解説
Bunが従来のNode.jsと比較して3倍以上高速である秘密は、その基盤技術と設計思想にあります。なぜBunはここまで高速なのか、その理由を技術的観点から見ていきましょう。
高速化の基盤技術:JavaScriptCoreエンジン
Bunの最大の特徴は、Node.jsやDenoで使用されているV8エンジンではなく、Appleが開発したJavaScriptCoreエンジン(Safariと同じエンジン)を採用している点です。JavaScriptCoreはメモリ消費が少なく、特に起動時間が短いという特徴があります。
// 実行速度の比較例
// Node.js
// $ time node -e "console.log('Hello World')"
// 実行時間: 約70-100ms
// Bun
// $ time bun -e "console.log('Hello World')"
// 実行時間: 約5-10ms
Zigプログラミング言語による実装
BunはJavaScriptやC++ではなく、メモリ安全性と高いパフォーマンスを両立する新しいプログラミング言語「Zig」で実装されています。Zigは低レベルな最適化が可能でありながら、安全性も確保されているため、Bunの内部実装に理想的な言語です。
最初からパフォーマンスを重視した設計
Bunは後方互換性や歴史的な制約よりも、パフォーマンスを最優先する設計思想で開発されています。例えば:
- 非同期I/Oの最適化
- JavaScriptモジュール解決の高速化
- 内部キャッシュの徹底活用
- 起動時のプリロードの最小化
ファイルシステムへのアクセス最適化
ファイルの読み書きは多くのWeb開発で頻繁に行われる操作ですが、Bunではこの部分が特に最適化されています。
// Node.jsの場合
const fs = require('fs/promises');
await fs.readFile('file.txt', 'utf8');
// Bunの場合
const text = await Bun.file('file.txt').text();
// より簡潔で高速
内蔵トランスパイラとバンドラー
Bunには高速なトランスパイラとバンドラーが内蔵されており、外部ツールに依存せずに直接TypeScriptやJSXを処理できます。これにより、開発中の変更反映も非常に高速です。
これらの技術的特徴により、Bunは特に以下のようなケースで顕著な速度向上を実現しています:
- 開発サーバーの起動時間(Viteより最大30倍高速)
- APIサーバーのレスポンス時間
- 大規模プロジェクトのビルド時間
- TypeScriptファイルの直接実行
ただし、すべての面でBunが優れているわけではありません。特に長時間動作するプロセスや非常に複雑な計算を行う場合には、V8エンジンの方が最適化の恩恵を受けられる場合もあります。用途に応じて適切に選択することが重要です。
Bunインストールから初めての実行まで
Bunを使い始めるには、まずお使いのシステムにインストールする必要があります。ここでは、主要なOSへのインストール方法と基本的な使い方を紹介します。
Bunのインストール
Bunは以下のOSをサポートしています:
- macOS (x64, ARM)
- Linux (x64, ARM)
- Windows (WSL経由)
macOSへのインストール
macOSでは、curlコマンドを使った一行インストールが最も簡単です。
curl -fsSL https://bun.sh/install | bash
Homebrewパッケージマネージャーからもインストールできます。
brew tap oven-sh/bun
brew install bun
Linuxへのインストール
Linuxでも、curlを使ったインストールが可能です。
curl -fsSL https://bun.sh/install | bash
Windowsへのインストール
Windowsでは、WSL (Windows Subsystem for Linux) を使用してBunを実行します。
まずWSLをインストールします。
wsl --install
WSL内でBunをインストールします。
curl -fsSL https://bun.sh/install | bash
インストールの確認
インストールが完了したら、以下のコマンドでBunのバージョンを確認できます。
bun --version
最新版が表示されれば、インストールは成功です。
最初のBunプロジェクト
新しいBunプロジェクトを始めるには、以下のコマンドを実行します。
mkdir my-bun-project
cd my-bun-project
bun init
bun init
コマンドを実行すると、対話形式で基本的なプロジェクト設定が行われます。すべてデフォルトでもOKですし、お好みに合わせて設定を変更することもできます。
最初のTypeScriptファイルの作成と実行
Bunの最大の特徴の一つは、TypeScriptファイルをネイティブに実行できることです。以下のようにTypeScriptファイルを作成してみましょう。
// index.ts
console.log("Hello from Bun!");
const server = Bun.serve({
port: 3000,
fetch(req) {
return new Response("Welcome to Bun!");
},
});
console.log(`Server running at http://localhost:${server.port}`);
このファイルを実行するには、次のコマンドを使います。
bun run index.ts
これだけで、TypeScriptファイルが直接実行され、簡単なWebサーバーが起動します。ブラウザでhttp://localhost:3000
にアクセスすると、「Welcome to Bun!」というメッセージが表示されます。
基本的なBunコマンド
Bunには多くの機能が含まれていますが、以下は日常的によく使う基本コマンドです。
# JavaScriptまたはTypeScriptファイルを実行
bun run <ファイル名>
# package.jsonのscriptsを実行
bun run <スクリプト名>
# パッケージをインストール
bun install <パッケージ名>
# 開発サーバーを起動(hot reloadingあり)
bun --hot <ファイル名>
# テストを実行
bun test
Bunは非常に高速なだけでなく、シンプルで直感的なAPIを提供しているため、初めての方でも短時間で基本的な使い方を習得できます。次のセクションでは、Bunのパッケージマネージャーとしての機能を詳しく見ていきましょう。
パッケージマネージャとしてのBunの使い方
Bunはランタイムだけでなく、高速なパッケージマネージャとしても機能します。npmやyarnの代わりとして使用でき、互換性を保ちながらパフォーマンスを大幅に向上させています。ここでは、Bunをパッケージマネージャとして使用する方法を見ていきましょう。
パッケージのインストール
基本的なパッケージのインストールは、bun install
コマンドを使用します。
# 単一パッケージのインストール
bun install express
# 複数パッケージのインストール
bun install express mongoose dotenv
# 開発用パッケージのインストール
bun install --dev typescript @types/express
# グローバルインストール
bun install -g typescript
Bunのパッケージインストールは従来のnpmやyarnと比較して非常に高速です。特に依存関係が多い大規模プロジェクトでは、その差が顕著になります。
package.jsonとの互換性
Bunは標準的なpackage.jsonファイルをサポートしており、既存のNode.jsプロジェクトをそのまま使うことができます。
{
"name": "my-bun-project",
"version": "1.0.0",
"module": "index.ts",
"type": "module",
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"typescript": "^5.0.0"
},
"scripts": {
"start": "bun run index.ts",
"dev": "bun --hot run index.ts",
"test": "bun test"
}
}
既存のpackage.jsonを持つプロジェクトでbun install
を実行すると、Bunは自動的にすべての依存関係をインストールします。
bun.lockb - バイナリロックファイル
Bunは依存関係をトラッキングするために、bun.lockb
という独自のバイナリロックファイルを生成します。このファイルはテキストベースの従来のロックファイル(package-lock.jsonやyarn.lock)と比較して、はるかに小さく、解析も高速です。
# ロックファイルの内容を表示
bun pm inspect
スクリプトの実行
package.jsonのscriptsセクションに定義されたスクリプトは、bun run
で実行できます。
# package.jsonのstartスクリプトを実行
bun run start
# テストを実行
bun run test
依存関係の管理
# プロジェクトの依存関係を更新
bun update
# 使用していない依存関係を検出
bun pm ls --unused
# 依存関係のセキュリティ脆弱性をチェック
bun pm audit
monorepoのサポート
Bunはmonorepo(複数のパッケージを含む単一リポジトリ)をサポートしており、workspacesを使用して複数のパッケージを効率的に管理できます。
// package.json
{
"name": "my-monorepo",
"workspaces": [
"packages/*"
]
}
特定のワークスペースでコマンドを実行するには:
# 特定のワークスペースでパッケージをインストール
bun install --cwd packages/my-package express
# 特定のワークスペースでスクリプトを実行
bun run --cwd packages/my-package start
npmとyarnとの比較
Bunのパッケージマネージャは、npmやyarnと比較して以下のような利点があります:
- 速度: 並列処理とバイナリロックファイルにより、インストールと解決が非常に高速
- ディスク容量: より効率的なキャッシング戦略により、ディスク使用量を削減
- シンプルさ: 直感的なAPIと少ないコマンドセット
- ネイティブなTypeScriptサポート: .tsファイルを直接実行可能
ただし、すべてのnpmパッケージが完全に互換性があるわけではないため、特に複雑な依存関係やネイティブモジュールを使用するプロジェクトでは注意が必要です。
Bunのパッケージマネージャは日々進化しており、将来的にはさらに多くの機能や互換性が追加される予定です。実際のプロジェクトでBunを使用する前に、重要な依存関係の互換性を確認することをお勧めします。
おすすめの書籍
Bunサーバーの構築方法と実践例
Bunには高性能なHTTPサーバーが組み込まれており、Node.jsよりもはるかに少ないコードと高速なパフォーマンスでWebサーバーを構築できます。ここでは、Bunを使ったサーバー構築の基本から応用例までを紹介します。
最もシンプルなBunサーバー
Bunのサーバーは非常にシンプルに構築できます。以下は最小限のコードでHTTPサーバーを立ち上げる例です。
// server.ts
const server = Bun.serve({
port: 3000,
fetch(req) {
return new Response("Hello World!");
},
});
console.log(`Server running at http://localhost:${server.port}`);
このコードをbun run server.ts
で実行すれば、すぐにサーバーが起動します。Node.jsと比較して、外部ライブラリのインポートや複雑な設定が不要なことがわかります。
リクエストのルーティング
実際のアプリケーションでは、URLに基づいて異なるレスポンスを返す必要があります。Bunではリクエストオブジェクトを使用して簡単にルーティングを実装できます。
// router.ts
const server = Bun.serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
// ルートパスへのリクエスト
if (url.pathname === "/") {
return new Response("Welcome to Bun Server!");
}
// APIエンドポイント
if (url.pathname === "/api/data") {
const data = { message: "This is JSON data", time: new Date() };
return new Response(JSON.stringify(data), {
headers: { "Content-Type": "application/json" },
});
}
// 静的ファイル
if (url.pathname.startsWith("/public/")) {
const filePath = url.pathname.replace("/public/", "");
const file = Bun.file(`./public/${filePath}`);
return new Response(file);
}
// 404 Not Found
return new Response("Not Found", { status: 404 });
},
});
console.log(`Router server running at http://localhost:${server.port}`);
RESTful APIの実装
Bunを使って完全なRESTful APIを構築する例を見てみましょう。
// api-server.ts
interface Todo {
id: number;
text: string;
completed: boolean;
}
// インメモリデータストア
const todos: Todo[] = [
{ id: 1, text: "Learn Bun", completed: false },
{ id: 2, text: "Build a server", completed: true },
];
const server = Bun.serve({
port: 3000,
async fetch(req) {
const url = new URL(req.url);
// CORS対応ヘッダー
const headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
};
// プリフライトリクエスト対応
if (req.method === "OPTIONS") {
return new Response(null, { headers });
}
// TODOsのエンドポイント
if (url.pathname === "/api/todos") {
// GETリクエスト - すべてのTODOを取得
if (req.method === "GET") {
return new Response(JSON.stringify(todos), {
headers: { ...headers, "Content-Type": "application/json" },
});
}
// POSTリクエスト - 新しいTODOを作成
if (req.method === "POST") {
const body = await req.json();
const newTodo: Todo = {
id: todos.length + 1,
text: body.text,
completed: false,
};
todos.push(newTodo);
return new Response(JSON.stringify(newTodo), {
headers: { ...headers, "Content-Type": "application/json" },
status: 201,
});
}
}
// 特定のTODOのエンドポイント
if (url.pathname.match(/^\/api\/todos\/\d+$/)) {
const id = parseInt(url.pathname.split("/").pop() || "0");
const todoIndex = todos.findIndex(todo => todo.id === id);
if (todoIndex === -1) {
return new Response(JSON.stringify({ error: "Todo not found" }), {
headers: { ...headers, "Content-Type": "application/json" },
status: 404,
});
}
// GETリクエスト - 特定のTODOを取得
if (req.method === "GET") {
return new Response(JSON.stringify(todos[todoIndex]), {
headers: { ...headers, "Content-Type": "application/json" },
});
}
// PUTリクエスト - 特定のTODOを更新
if (req.method === "PUT") {
const body = await req.json();
todos[todoIndex] = { ...todos[todoIndex], ...body };
return new Response(JSON.stringify(todos[todoIndex]), {
headers: { ...headers, "Content-Type": "application/json" },
});
}
// DELETEリクエスト - 特定のTODOを削除
if (req.method === "DELETE") {
const deletedTodo = todos.splice(todoIndex, 1)[0];
return new Response(JSON.stringify(deletedTodo), {
headers: { ...headers, "Content-Type": "application/json" },
});
}
}
// 404 Not Found
return new Response(JSON.stringify({ error: "Not Found" }), {
headers: { ...headers, "Content-Type": "application/json" },
status: 404,
});
},
});
console.log(`API server running at http://localhost:${server.port}`);
既存のExpressアプリケーションの移行
Node.jsのExpressフレームワークを使用している場合、Bunでも同様に動作させることができます。
// express-app.ts
import express from 'express';
const app = express();
app.use(express.json());
app.get('/', (req, res) => {
res.send('Express running on Bun!');
});
app.get('/api/hello', (req, res) => {
res.json({ message: 'Hello from Express on Bun!' });
});
export default app;
// express-server.ts
import app from './express-app';
// Expressアプリをポート3000で起動
app.listen(3000, () => {
console.log('Express server running on Bun at http://localhost:3000');
});
このExpressアプリケーションをbun run express-server.ts
で実行することができます。既存のExpressアプリケーションをBunに移行する際は、このように最小限の変更で対応できる場合が多いです。
Bunサーバーのパフォーマンス最適化
Bunサーバーは最初から高性能ですが、さらに最適化するためのテクニックをいくつか紹介します。
- ストリーミングレスポンス:
const server = Bun.serve({
port: 3000,
fetch(req) {
// 大きなファイルのストリーミング
const file = Bun.file("large-data.csv");
return new Response(file.stream());
},
});
- サーバーサイドキャッシュ:
// シンプルなインメモリキャッシュ
const cache = new Map();
const server = Bun.serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
// キャッシュからレスポンスをチェック
if (cache.has(url.pathname)) {
return cache.get(url.pathname);
}
// 新しいレスポンスを生成
const response = new Response(`Content for ${url.pathname}`);
// キャッシュに保存(実際のアプリではTTLを設定する)
cache.set(url.pathname, response.clone());
return response;
},
});
Bunサーバーは非常に柔軟で、小規模なAPIから大規模なWebアプリケーションまで、さまざまなユースケースに対応できます。内部的に最適化されたHTTPスタックにより、Node.jsベースのサーバーよりも高いパフォーマンスを発揮し、特に大量のリクエストを処理する必要があるアプリケーションで威力を発揮します。
Bunと他のツールの互換性と移行のポイント
Bunは既存のJavaScriptエコシステムとの互換性を高めることを目指していますが、現時点では完全な互換性はまだ実現されていません。ここでは、Bunと他のJavaScriptツールとの互換性や、既存のプロジェクトを移行する際のポイントについて解説します。
Node.jsとの互換性
Bunは多くのNode.jsのAPIと互換性がありますが、一部の機能は異なる動作をするか、まだ実装されていない場合があります。
// Node.jsとBunの両方で動作するコード例
import fs from 'fs';
import path from 'path';
const filePath = path.join(process.cwd(), 'data.txt');
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf8');
console.log(content);
}
ただし、次のような違いに注意が必要です:
- Bunの
process.env
はイミュータブル(変更不可) - 一部のNode.js固有のAPIはサポートされていない
- CommonJSとESMの扱いに違いがある
移行前の互換性チェック
既存のNode.jsプロジェクトをBunに移行する前に、互換性をチェックするためのステップを紹介します:
- 依存関係のチェック:
# 依存関係のチェックツールを実行
bun run --bun node_modules/.bin/check-compat
- 徐々に移行する:
まずはテストやビルドプロセスなど、一部の機能だけをBunに移行することから始めると良いでしょう。例えば:
// package.json
{
"scripts": {
"start": "node index.js",
"start:bun": "bun run index.js",
"test": "jest",
"test:bun": "bun test"
}
}
主要フレームワークとの互換性
主要なJavaScriptフレームワークのBunとの互換性状況をまとめました:
フレームワーク | 互換性 | 注意点 |
---|---|---|
Express | ✅ 良好 | ほとんどの機能が動作 |
Next.js | 🟡 部分的 | 開発サーバーはOK、一部のAPI Routes機能に制限あり |
React | ✅ 良好 | JSX変換は内蔵されているため高速 |
Vue | 🟡 部分的 | 基本機能は動作するが一部のプラグインに問題あり |
Svelte | ✅ 良好 | コンパイルはBun内蔵のため高速 |
バンドラーとしてのBun
BunはWebpackやViteのような従来のバンドラーの代替としても使用できます。
# プロジェクトをバンドル
bun build ./index.ts --outdir ./dist
# 開発サーバー起動
bun --hot ./index.ts
バンドラーとしてのBunの特徴:
- ネイティブなTypeScriptとJSXのサポート
- デフォルトで最小限の設定で動作
- 非常に高速なビルド時間
.env
ファイルの自動ロード
ただし、まだWebpackやViteほど多様なプラグインエコシステムはないため、特殊なビルド要件がある場合は注意が必要です。
テストランナーとしての互換性
Bunには組み込みのテストランナーが含まれており、Jest互換のAPIを提供します。
// sum.test.ts
import { test, expect } from "bun:test";
test("2 + 2 = 4", () => {
expect(2 + 2).toBe(4);
});
test("JSON parse/stringify", () => {
const obj = { hello: "world" };
expect(JSON.parse(JSON.stringify(obj))).toEqual(obj);
});
Jestユーザーにとって馴染みのある機能が多いですが、一部のJestの高度な機能(特定のモック機能など)はまだ完全にはサポートされていません。
本番環境への移行のポイント
Bunを本番環境で使用する際の注意点:
- 安定性の確認: Bunは急速に発展していますが、重要な本番環境では安定バージョンを使用
- モニタリング: 初期段階ではメモリ使用量やパフォーマンスを注意深くモニタリング
- フォールバック: 重要な機能では、Node.jsへのフォールバックを準備
- 依存関係の検証: すべての依存関係がBunと互換性があることを徹底的にテスト
Bunは非常に有望なツールですが、現時点ではNode.jsの完全な代替とはなっていません。用途や要件に応じて、適切に使い分けることが重要です。新しいプロジェクトや開発環境では積極的に採用し、本番環境への導入は慎重に検討することをお勧めします。
また、Bunはアクティブに開発が続けられているプロジェクトであり、日々改善されています。今後はさらに互換性が向上し、より多くのユースケースで安心して使用できるようになるでしょう。