Node.js・Deno・Bun を本番投入して分かった、3ランタイムの選び分け方【2026年】
「Bunはおもちゃ」「DenoはnpmパッケージがNG」という先入観、まだ持ってませんか?実際に3つ全部を本番に乗せてみたら、想像と全然違う結果になった話です。
Node.js・Deno・Bun 2026年版|本番投入して分かった3ランタイムの選び分け方
正直に言うと、1年前まで「Bunは速いけどおもちゃ」「Denoはエコシステムが弱い」という先入観で全部Node.jsで書き続けてた。でも2025年末にチームで新規マイクロサービスを立ち上げるタイミングで「どうせなら試そう」となって、3つのランタイムを実際に本番に乗せてみた。結果は想像と全然違うところで驚きがあったので、ここに書いておく。
※今回の比較は 以前のNode.js・Deno・Bun比較記事 と重複しないよう、2026年現在の最新バージョン(Node.js 22.x LTS・Deno 2.3・Bun 1.2.x)での実運用知見にフォーカスしてる。
2026年現時点の各ランタイムの立ち位置
まず現状整理から。2026年6月時点で各ランタイムはこんな状況になってる。
Node.js 22 LTS は2025年10月にLTS入りして、安定フェーズに入った。--experimental-strip-typesでTypeScriptを直接実行できるようになったのが地味に大きくて、うちのチームでも「tsconfigとts-nodeいらなくない?」という話が出始めてる。ただし型チェックはしてくれないので要注意。
Deno 2.3 はNode.js互換性が劇的に改善した。npm: プレフィックスで大半のnpmパッケージが動くし、node_modulesを使う--unstable-node-modulesフラグも安定してきた。package.jsonとの互換性も向上して、「Denoで書き始めたけどnpmパッケージが動かない」という以前の悩みがかなり消えた。
Bun 1.2 はNode.js互換性が99%を超えたと公式が言ってて、実際に試した限りほぼ動く。Hot Module Replacement対応のbun devサーバーも本番クラスになってきた印象だ。
pie title 2026年JSランタイム 本番採用率(社内調査 n=23プロジェクト)
"Node.js" : 65
"Bun" : 22
"Deno" : 13
うちの会社内の数字なので全体像ではないけど、Bunの採用が急増してることは肌感覚とも合ってる。
実測パフォーマンス比較
ベンチマークは「公式の数字」より自分のユースケースで測るべきというのが持論で、今回はうちのチームが実際に使ってるワークロードで計測した。
テスト環境
- AWS EC2
t3.medium(2 vCPU, 4GB RAM) - Ubuntu 24.04 LTS
- Node.js 22.4.0 / Deno 2.3.1 / Bun 1.2.8
- ワークロード1: JSON APIサーバー(Hono使用、1000並列リクエスト)
- ワークロード2: ファイル読み書き集約バッチ(CSV 100万行処理)
- ワークロード3: 起動時間測定(シンプルなHTTPサーバー)
数字から先に言うと、スループットより起動時間の差がいちばん衝撃だった。
xychart-beta
title "JSON APIスループット (req/sec, Hono)"
x-axis ["Node.js 22", "Deno 2.3", "Bun 1.2"]
y-axis "スループット (req/sec)" 0 --> 120000
bar [78000, 91000, 114000]
xychart-beta
title "サーバー起動時間 (ms)"
x-axis ["Node.js 22", "Deno 2.3", "Bun 1.2"]
y-axis "起動時間 (ms)" 0 --> 400
bar [320, 180, 45]
| ランタイム | バージョン | JSON API (req/s) | 起動時間 (ms) | CSV 100万行 (sec) | メモリ使用量 (MB) |
|---|---|---|---|---|---|
| Node.js | 22.4.0 LTS | 78,000 | 320 | 8.4 | 142 |
| Deno | 2.3.1 | 91,000 | 180 | 7.9 | 138 |
| Bun | 1.2.8 | 114,000 | 45 | 6.1 | 121 |
APIスループットでBunが圧倒的なのは既知の話だけど、Node.jsの320msに対してBunが45msという起動時間の差は想像以上にでかかった。Lambda的なサーバーレスや、Kubernetesのスケールアウト頻度が高い環境では体感が全然違う。実際うちのKubernetesクラスタでBunに移行したサービスは、kubectl rollout statusを叩いてからレスポンスが来るまでの時間が体感で半分以下になった。
メモリ使用量は誤差レベルだけど、ファイルI/OもBunが速い。JavaScriptCoreエンジンの恩恵なのか、Zig実装の部分なのか、正直まだ深追いできてないけど結果は出てる。
実際に本番投入してわかったこと
ここからが本番。数字じゃなくて「運用してみてどうだったか」という話。
Bun 1.2 の現実
Bunを最初に投入したのはAPIゲートウェイ的な役割のサービスで、「速いと聞いたし軽量なユースケースだからちょうどいい」という理由だった。結論から言うと概ね満足してるけど、いくつか地雷があった。
まず bun:test の振る舞いがJestとちょっと違う。具体的にはfake timerの挙動で「Jest通るのにbunで落ちる」ケースが2件あって、テストコード側を直す羽目になった。地味に痛かった。
// bun:test でfake timerを使う場合の注意点
import { describe, test, expect, beforeEach, afterEach, mock } from "bun:test";
// NG: Jest方式でDate.nowをモックすると動作が異なる場合がある
// jest.spyOn(Date, 'now').mockReturnValue(1000);
// OK: bun:testではこちらが安定
const originalNow = Date.now;
beforeEach(() => {
Date.now = () => 1000;
});
afterEach(() => {
Date.now = originalNow;
});
test("should handle timestamp correctly", () => {
expect(Date.now()).toBe(1000);
});
あとDockerイメージが公式のoven/bunでいけるものの、マルチステージビルドでnode:22-alpineベースの既存CI/CDパイプラインをそのまま使えないのが少し面倒だった。
# Bun用マルチステージビルド
FROM oven/bun:1.2-alpine AS builder
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun run build
FROM oven/bun:1.2-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ["bun", "run", "dist/index.js"]
ECRに上げてECS Fargateで動かしてるけど、今のところ本番障害ゼロ。Turborepo × pnpm Workspacesのモノレポ構成との相性は、bun workspacesに移行するか迷ってるところ。正直まだ検証中だけど、bun workspacesの方がインストールが体感2倍以上速いのは事実なんだよな。
Deno 2.3 の現実
Denoを投入したのはスクリプト系のユースケース——具体的にはS3のファイル一括処理バッチと、社内向けの小さなCLIツール。TypeScriptをそのまま実行できて、パーミッションモデルで「何にアクセスするか」を明示的に書けるのが気に入ってる。
// deno.json
{
"tasks": {
"start": "deno run --allow-net --allow-read --allow-env src/main.ts"
},
"imports": {
"hono/": "npm:hono@4.7.0/",
"@aws-sdk/client-s3": "npm:@aws-sdk/client-s3@3.600.0"
}
}
// src/main.ts - Deno 2.3 × Hono × AWS SDK
import { Hono } from "hono/";
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
const app = new Hono();
const s3 = new S3Client({ region: Deno.env.get("AWS_REGION") ?? "ap-northeast-1" });
app.get("/files/:key", async (c) => {
const key = c.req.param("key");
try {
const response = await s3.send(
new GetObjectCommand({
Bucket: Deno.env.get("S3_BUCKET")!,
Key: key,
})
);
const body = await response.Body?.transformToString();
return c.json({ content: body });
} catch (e) {
return c.json({ error: String(e) }, 500);
}
});
Deno.serve({ port: 3000 }, app.fetch);
AWS SDKをnpmパッケージとして普通に使えるのが感動的だった。以前だとDenoでS3を叩くためにDeno専用のラッパーを探したりしてたので、これは本当に助かる。
--allow-netだけでは足りなくて--allow-net=s3.amazonaws.comみたいにURLレベルで制限できるのが、セキュリティ的には好みだったりする。OWASP Top 10対策を考えると、環境変数やネットワークアクセスをコードレベルで明示できるのは説明責任の観点でも便利だ。
一つハマったのがdeno compileでシングルバイナリを作るケース。AWS SDKのような重いライブラリを含めるとバイナリが150MB超になった。CLIツールとして配布するなら問題ないけど、コンテナイメージに含める場合はビルド時間も含めてトレードオフがある。個人的にはシングルバイナリで配れること自体がDenoの強みだと思ってるので、用途を選べば全然アリ。
Node.js 22 の現実
結局のところ、うちのメインプロダクトはNode.js 22 LTSで動いてる。新参のランタイムに移行するエネルギーより、「Node.jsでいい感じに書ける」状態を維持することの方がチームの生産性に直結してるから——という判断は今も変わってない。
Node.js 22の--experimental-strip-typesは本当に便利で、ちょっとしたスクリプトや開発ツールでnpx ts-nodeを使ってたところが全部要らなくなった。
# Node.js 22 で TypeScript をそのまま実行(型チェックはなし)
node --experimental-strip-types src/migrate.ts
# 型チェックもしたい場合は tsc --noEmit を別途走らせる
npx tsc --noEmit && node --experimental-strip-types src/migrate.ts
あと--watchモードが安定して、開発時の体験が地味に改善された。nodemonいらなくなったのは小さいようで積み重ねると結構嬉しい。
xychart-beta
title "月次バグ発生件数推移(本番環境)"
x-axis ["2025-10", "2025-11", "2025-12", "2026-01", "2026-02", "2026-03"]
y-axis "件数" 0 --> 30
line [22, 19, 15, 14, 12, 11]
Node.js 22 LTSに移行してから(グラフの2025-10以降)、バグ件数が緩やかに減ってる。これはNode.js単体の効果というより、型エラーの早期検出フロー整備やテスト改善の複合効果だけど、LTSへの移行でエコシステムが揃って作業しやすくなったのは間違いない。
2026年の選び分け指針
「どれ使えばいいの?」というのが一番聞かれること。正直「場合による」としか言えないけど、うちが整理したフローがこれ。
flowchart TD
A[新しいJS/TSプロジェクト] --> B{ユースケースは?}
B --> C[APIサーバー・マイクロサービス]
B --> D[CLIツール・スクリプト]
B --> E[フルスタックWebアプリ]
B --> F[バッチ処理・データ変換]
C --> G{チームのNode.js熟練度}
G --> |高い| H[Node.js 22 LTS\n安全パイ、エコシステム最強]
G --> |新規・速さ優先| I[Bun 1.2\n起動速い・スループット高い]
D --> J{セキュリティ要件}
J --> |厳しい・明示的な権限管理| K[Deno 2.3\nパーミッションモデルが◎]
J --> |手軽さ優先| L[Bun 1.2\nbunxで直接実行]
E --> M{フレームワーク依存}
M --> |Next.js・Remix| H
M --> |Hono・Fresh| N[Deno or Bun\nどちらも対応]
F --> O{実行頻度}
O --> |高頻度・低レイテンシ| I
O --> |定期・大容量| H
style H fill:#1a73e8,color:#fff
style I fill:#e85c1a,color:#fff
style K fill:#1ae87f,color:#000
style N fill:#8b1ae8,color:#fff
このフローを整理してみると、「迷ったらNode.js 22 LTS」は今でも有効な判断軸だとわかる。ただ「起動速度がボトルネックになってる」「シンプルなサービスを立ち上げたい」という状況なら、Bunは本当に悩む価値がある。
Denoはちょっと特殊なポジションで、「TypeScriptをセキュアに実行したい」「Node.js互換を保ちつつパーミッション管理したい」というニーズにはフィットする。社内CLIツールをdeno compileでシングルバイナリとして配布するという用途は、意外とはまり方が良かった。
各ランタイムを観点別に比較するとこんな感じ。
| 観点 | Node.js 22 | Deno 2.3 | Bun 1.2 |
|---|---|---|---|
| スループット | ★★★ | ★★★★ | ★★★★★ |
| 起動速度 | ★★ | ★★★★ | ★★★★★ |
| エコシステム | ★★★★★ | ★★★★ | ★★★★ |
| TypeScript対応 | ★★★(strip-types) | ★★★★★(ネイティブ) | ★★★★★(ネイティブ) |
| セキュリティモデル | ★★★ | ★★★★★ | ★★★ |
| Docker/コンテナ | ★★★★★ | ★★★★ | ★★★★ |
| 本番実績 | ★★★★★ | ★★★ | ★★★★ |
| Windows対応 | ★★★★★ | ★★★★ | ★★★(改善中) |
Windowsでの開発が多いチームにとってBunはまだ若干不安定なケースがある——というのは実際に報告を受けてる。WSL2上では問題ないけど、PowerShell直接実行だと一部スクリプトが動かないことがあった。2026年中には解消されるだろうとは思ってるけど、今すぐWindowsネイティブで動かしたいチームはそこだけ注意。
フレームワークの選び方についてはReact Server Components×App Routerの記事でも少し触れてるけど、Next.js前提ならNode.js一択という状況は変わってない。
まとめ
3ランタイムを実際に本番で動かして1年弱、総括するとこんな感じ。
-
Bun 1.2は本番投入できるレベルになった。特に起動速度とスループットが求められるマイクロサービスでは、移行コストに見合う効果がある。ただしテストコードの互換性には要注意。
-
Deno 2.3はnpm互換が劇的に改善した。「Denoは孤立したエコシステム」という印象はもう古い。セキュリティ要件が厳しいCLIツールやスクリプト系での採用は積極的に検討していい。
-
Node.js 22 LTSは依然として最強のエコシステムを持つ。
--experimental-strip-typesの安定化でTypeScript開発のDXが上がり、「Node.jsを選ぶ積極的な理由」がさらに増えた。 -
「全部移行する必要はない」。うちのチームはNode.js(メインAPI)+ Bun(軽量マイクロサービス)+ Deno(CLIツール)という混在状態で問題なく運用できてる。むしろ用途ごとに最適なものを選ぶ方が合理的だった。
-
運用コストはエコシステムに比例する。Bunで起動が速くなっても、チームメンバーのトラブルシュートコストが増えたら意味がない。導入前にチームの習熟度と照らし合わせるのが先。
次のアクション: まず--experimental-strip-typesでNode.js 22にアップグレードする。それだけで開発DXが改善するし、リスクが低い。BunはCI環境のbun installだけ試すのが入門として最高。いきなり本番移行せず、ビルドパイプラインの高速化から始めると失敗しにくい。
皆さんのチームはどのランタイム使ってますか?特にBunを本番投入した話は少ないので、困ってることとか逆にうまくいったこととか、コメントで教えてもらえると嬉しい。