Node.jsの代替として注目を集めているBun。2025年、Bun 1.1でWindows対応を果たし、さらにBun 1.2.19ではパフォーマンスが大幅に向上しました。本記事では、実際のプロジェクトでNode.jsからBunへ移行する具体的な手順と実践的なノウハウを詳しく解説します。
なぜ今Bunなのか?
Bunは単なるJavaScriptランタイムではありません。パッケージマネージャー、バンドラー、テストランナー、タスクランナーが統合された開発体験を提供します。
Bunの主要な優位性
- 統合開発体験: npm、webpack、jest、nodeを1つのツールで代替
- 高速パフォーマンス: JavaScriptCoreエンジンによる高速実行
- クロスプラットフォーム: Windows、macOS、Linux対応(2025年時点)
- 互換性重視: 既存のNode.jsプロジェクトとnpmライブラリが動作
最短で課題解決する一冊
この記事の内容と高い親和性が確認できたベストマッチです。早めにチェックしておきましょう。
Bunのインストール
macOS・Linux
curl -fsSL https://bun.sh/install | bashWindows(PowerShell)
irm bun.sh/install.ps1 | iexインストール確認
bun --version
# 出力例: 1.2.19さらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。
実際のプロジェクトで移行体験
Express.jsを使った実際のAPIサーバーをNode.jsからBunへ移行してみましょう。
1. 既存のNode.jsプロジェクト
// server.js - Node.js版
import express from 'express';
import cors from 'cors';
import { readFile } from 'fs/promises';
const app = express();
const PORT = process.env.PORT || 3000;
app.use(cors());
app.use(express.json());
// ファイル読み込みのパフォーマンステスト用エンドポイント
app.get('/api/data', async (req, res) => {
try {
const data = await readFile('./data/sample.json', 'utf8');
const parsed = JSON.parse(data);
// 重い処理をシミュレート(配列の変換処理)
const processed = parsed.items.map(item => ({
...item,
processed: true,
timestamp: new Date().toISOString()
}));
res.json({
success: true,
data: processed,
processedAt: Date.now()
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(PORT, () => {
console.log(`Node.js server running on port ${PORT}`);
});2. Bunに最適化されたバージョン
// server.js - Bun版
import { serve } from 'bun';
const server = serve({
port: process.env.PORT || 3000,
async fetch(req) {
const url = new URL(req.url);
// CORS対応
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
};
if (req.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
// APIルーティング
if (url.pathname === '/api/data' && req.method === 'GET') {
try {
// Bunの高速ファイル読み込みAPI使用
const file = Bun.file('./data/sample.json');
const data = await file.json();
// データ処理(Bunの最適化されたJavaScriptCoreで実行)
const processed = data.items.map(item => ({
...item,
processed: true,
timestamp: new Date().toISOString()
}));
return Response.json({
success: true,
data: processed,
processedAt: Date.now(),
runtime: 'Bun'
}, { headers: corsHeaders });
} catch (error) {
return Response.json(
{ error: error.message },
{ status: 500, headers: corsHeaders }
);
}
}
// 404処理
return new Response('Not Found', { status: 404, headers: corsHeaders });
},
});
console.log(`Bun server running on port ${server.port}`);3. パッケージ管理の移行
# Node.js プロジェクトの依存関係をBunで管理
rm -rf node_modules package-lock.json
# Bunで依存関係をインストール
bun install
# 新しい依存関係の追加
bun add express cors
bun add -d @types/node typescript
# 開発用依存関係の追加
bun add -d nodemon concurrently4. スクリプトの最適化
{
"name": "node-to-bun-migration",
"version": "1.0.0",
"scripts": {
"dev": "bun --watch server.js",
"start": "bun server.js",
"build": "bun build ./src/index.ts --outdir ./dist --target node",
"test": "bun test",
"type-check": "bunx tsc --noEmit"
},
"dependencies": {
"express": "^4.19.2",
"cors": "^2.8.5"
},
"devDependencies": {
"@types/node": "^20.14.12",
"typescript": "^5.5.4"
}
}さらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。
パフォーマンス比較テスト
実際のパフォーマンステストを行いました。
ベンチマークスクリプト
// benchmark.js - パフォーマンステスト用スクリプト
import { performance } from 'perf_hooks';
// ファイル読み込み速度テスト
async function fileReadTest() {
const iterations = 1000;
const start = performance.now();
for (let i = 0; i < iterations; i++) {
// Bunの場合: Bun.file() API使用
// Node.jsの場合: fs.readFile() 使用
if (typeof Bun !== 'undefined') {
const file = Bun.file('./data/sample.json');
await file.json();
} else {
const { readFile } = await import('fs/promises');
const data = await readFile('./data/sample.json', 'utf8');
JSON.parse(data);
}
}
const end = performance.now();
return end - start;
}
// HTTP サーバー起動速度テスト
async function serverStartupTest() {
const start = performance.now();
if (typeof Bun !== 'undefined') {
// Bunの場合
const server = Bun.serve({
port: 0,
fetch: () => new Response('OK')
});
server.stop();
} else {
// Node.jsの場合
const express = (await import('express')).default;
const app = express();
const server = app.listen(0);
server.close();
}
const end = performance.now();
return end - start;
}
// ベンチマーク実行
async function runBenchmarks() {
const runtime = typeof Bun !== 'undefined' ? 'Bun' : 'Node.js';
console.log(`${runtime} パフォーマンステスト結果:`);
const fileTime = await fileReadTest();
console.log(`ファイル読み込み (1000回): ${fileTime.toFixed(2)}ms`);
const startupTime = await serverStartupTest();
console.log(`サーバー起動時間: ${startupTime.toFixed(2)}ms`);
}
runBenchmarks().catch(console.error);テスト実行
# Node.jsでの実行
node benchmark.js
# Bunでの実行
bun benchmark.js結果例(筆者の環境)
Node.js パフォーマンステスト結果:
ファイル読み込み (1000回): 1247.83ms
サーバー起動時間: 23.45ms
Bun パフォーマンステスト結果:
ファイル読み込み (1000回): 892.31ms
サーバー起動時間: 8.72msさらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。
実用的な移行チェックリスト
✅ 移行前の確認事項
// migration-check.js - 移行前の互換性チェック
import { execSync } from 'child_process';
import { readFileSync } from 'fs';
function checkProjectCompatibility() {
console.log('🔍 Bun互換性チェックを開始...\n');
// package.json の確認
const packageJson = JSON.parse(readFileSync('./package.json', 'utf8'));
// 問題のある依存関係をチェック
const problematicPackages = [
'node-gyp', // ネイティブモジュール
'bcrypt', // バイナリ依存
'sharp', // 画像処理
'sqlite3' // データベース系
];
const dependencies = {
...packageJson.dependencies || {},
...packageJson.devDependencies || {}
};
const issues = problematicPackages.filter(pkg =>
Object.keys(dependencies).includes(pkg)
);
if (issues.length > 0) {
console.log('⚠️ 注意が必要なパッケージが見つかりました:');
issues.forEach(pkg => {
console.log(` - ${pkg}: 互換性テストが推奨されます`);
});
} else {
console.log('✅ 主要な互換性問題は見つかりませんでした');
}
// Node.jsのバージョン固有API使用をチェック
try {
const srcFiles = execSync('find ./src -name "*.js" -o -name "*.ts"',
{ encoding: 'utf8' }).split('\n').filter(Boolean);
const nodeSpecificPatterns = [
'process.version',
'require.resolve',
'__dirname',
'__filename'
];
srcFiles.forEach(file => {
const content = readFileSync(file, 'utf8');
nodeSpecificPatterns.forEach(pattern => {
if (content.includes(pattern)) {
console.log(`⚠️ ${file}: ${pattern} の使用を確認してください`);
}
});
});
} catch (error) {
console.log('ℹ️ ソースファイルのスキャンをスキップしました');
}
}
checkProjectCompatibility();🛠️ 段階的移行手順
#!/bin/bash
# migrate-to-bun.sh - 自動化された移行スクリプト
echo "🚀 Node.js → Bun 移行スクリプト"
# Step 1: バックアップ作成
echo "📦 プロジェクトのバックアップを作成..."
cp -r . ../$(basename "$PWD")-backup-$(date +%Y%m%d)
# Step 2: 既存の依存関係クリア
echo "🧹 既存の依存関係をクリア..."
rm -rf node_modules
rm -f package-lock.json yarn.lock
# Step 3: Bunでの再インストール
echo "📥 Bunで依存関係を再インストール..."
bun install
# Step 4: テスト実行
echo "🧪 テストを実行..."
if bun test; then
echo "✅ テストが成功しました"
else
echo "❌ テストでエラーが発生しました。修正が必要です。"
exit 1
fi
# Step 5: 開発サーバー起動テスト
echo "🌐 開発サーバーのテスト..."
timeout 10s bun run dev &
sleep 5
if curl -f http://localhost:3000 > /dev/null 2>&1; then
echo "✅ サーバーが正常に起動しました"
pkill -f "bun run dev"
else
echo "⚠️ サーバー起動に問題がある可能性があります"
pkill -f "bun run dev"
fi
echo "🎉 移行プロセスが完了しました!"さらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。
トラブルシューティング
よくある問題と解決策
1. ESMインポートエラー
// ❌ 問題のあるコード
const express = require('express');
// ✅ 修正版 - ESMを使用
import express from 'express';
// CommonJS混在時の対応
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const legacyModule = require('legacy-commonjs-module');2. 環境変数の処理
// ❌ Node.js特有の処理
process.env.NODE_ENV = 'production';
// ✅ Bun対応版
import { env } from 'process';
env.NODE_ENV = 'production';
// または process.env を直接使用(Bunでも動作)
process.env.NODE_ENV = 'production';3. ファイルパス処理
// ❌ Node.js特有の __dirname
const configPath = path.join(__dirname, 'config.json');
// ✅ ESM対応版
import { fileURLToPath } from 'url';
import path from 'path';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const configPath = path.join(__dirname, 'config.json');
// 🚀 Bun推奨版
const configPath = new URL('./config.json', import.meta.url).pathname;さらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。
プロダクション対応
Docker化
# Dockerfile - Bun対応版
FROM oven/bun:1.2.19-slim
WORKDIR /app
# 依存関係のインストール(キャッシュ効率化)
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile --production
# アプリケーションコード
COPY . .
# 本番環境用の最適化
ENV NODE_ENV=production
ENV BUN_ENV=production
# ヘルスチェック
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
EXPOSE 3000
# Bunでアプリケーション実行
CMD ["bun", "start"]CI/CD パイプライン
# .github/workflows/bun-ci.yml
name: Bun CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: '1.2.19'
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Type check
run: bunx tsc --noEmit
- name: Run tests
run: bun test
- name: Build application
run: bun run build
- name: Performance benchmark
run: bun run benchmarkまとめ
Bunへの移行は、適切な準備と段階的なアプローチによって実現できます。
移行のメリット
- 開発体験の向上: 統合されたツールチェーン
- パフォーマンス向上: 起動時間とファイルI/Oの高速化
- モダンな開発環境: TypeScript、ESMのネイティブサポート
移行時の注意点
- 段階的な移行: 一度にすべてを変更しない
- 十分なテスト: 既存の機能が正常に動作することを確認
- チーム全体での合意: 新しいツールセットへの学習コスト
2025年現在、BunはNode.jsの実用的な代替選択肢として十分成熟しています。本記事の手順を参考に、ぜひあなたのプロジェクトでもBunを試してみてください。
さらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。






![Pythonクローリング&スクレイピング[増補改訂版] -データ収集・解析のための実践開発ガイド-](https://m.media-amazon.com/images/I/41M0fHtnwxL._SL500_.jpg)