Node.js・Deno・Bun、実際に本番投入して比較してみた結果

3つのランタイムを6ヶ月本番運用。パフォーマンス・開発体験・運用コストの現実と、プロジェクト別の選び方をデータで解説します。

Node.js・Deno・Bun、本当はどれを選ぶべき?

去年のプロジェクトで「次のマイクロサービス、どのランタイム使おう」って議論になったんですよ。チームは安定重視でNode.jsを推してたけど、僕はずっとDeno触ってたし、BunはもうV1を超えてるし——結局、3つ全部本番で試してみることにしたんです。

6ヶ月運用して見えてきたのは「○○が最強」みたいな話じゃなくて、本当に「何を優先するか」次第だということ。実装とメトリクスベースで、その辺りを話します。

パフォーマンス:ベンチマークの信じられない話

最初、公式ベンチマークを見たときは「Bunめっちゃ速い」って思ったんですよ。でも本番で動かしたら全然違うんです。

簡単なHTTPサーバーで比較してみました。以下のコードを3つで実装して、実測してみたんですよ:

// Node.js (Express)
const express = require('express');
const app = express();

app.get('/api/users/:id', (req, res) => {
  res.json({ id: req.params.id, name: `User ${req.params.id}` });
});

app.listen(3000);
// Deno
import { serve } from "https://deno.land/std@0.208.0/http/server.ts";

serve((req: Request) => {
  const url = new URL(req.url);
  if (url.pathname.startsWith("/api/users/")) {
    const id = url.pathname.split("/").pop();
    return new Response(
      JSON.stringify({ id, name: `User ${id}` }),
      { headers: { "Content-Type": "application/json" } }
    );
  }
  return new Response("Not found", { status: 404 });
}, { port: 3000 });
// Bun
import { serve } from "bun";

serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);
    if (url.pathname.startsWith("/api/users/")) {
      const id = url.pathname.split("/").pop();
      return Response.json({ id, name: `User ${id}` });
    }
    return new Response("Not found", { status: 404 });
  },
});

同じロジックでやって、Apache Benchで100並行・10,000リクエストをぶん回してみたんです。結果がこれです。

xychart-beta
  title "単純HTTPサーバー 100並行 10,000リクエスト"
  x-axis [Node.js, Deno, Bun]
  y-axis "レスポンスタイム (ms)" 0 --> 150
  line [120, 95, 78]

Bunが速いのは事実なんですけど、正直どれもこのレベルの差なら本番では誤差ですよね。でも、メモリ使用量を見ると、また違う話になるんです。

xychart-beta
  title "メモリ使用量(アイドル状態)"
  x-axis [Node.js, Deno, Bun]
  y-axis "メモリ (MB)" 0 --> 120
  bar [110, 65, 88]

ここで気づいたのは、Denoが本当に軽い。Bunは言語仕様が独自だから、NPMパッケージ使いまくるとメモリが跳ねるんですよ。Node.jsは…まあ、V8なので仕方ない。

開発体験:型安全性と野蛮さのバランス

実装進めてくと、本当に差が出るんです。

Node.js:野蛮だけど自由

Node.jsは型がない(JavaScriptなので)。TypeScript使っても結局JSに変換されるんで、型は「開発時の補助」に過ぎない。そのぶん自由度は高いんですよ。

うちのチームは年季が入ってるので「型チェックなんかより、テスト書け」という文化があるんですよ。実装スピードは圧倒的に速い。npm生態系も成熟してて、「○○したい」で大体パッケージ見つかるんです。

ただしバージョン管理の地獄は覚悟してください。依存パッケージの更新が関連性のカオスになることは日常茶飯事。

Deno:型安全性の優等生

// Denoだと、ファイルI/O時点で型推論されるのが強い
const data = await Deno.readTextFile("./data.json");
const parsed = JSON.parse(data); // 型はanyだけど...

// こういうのは型安全
import { assertEquals } from "https://deno.land/std@0.208.0/testing/asserts.ts";

Deno.test("addition", () => {
  assertEquals(1 + 1, 2);
});

Denoの利点は「TypeScriptが一級市民」ってこと。セットアップの煩雑さが本当に少ないんですよ。あと「セキュリティ」がデフォルトで厳格。ファイルアクセスするなら--allow-read、ネットワーク使うなら--allow-netを付けないと動かないんです。大規模チームだと地味に効果的です。

ただし、npm生態系との統合が微妙なんですよね。Node.jsパッケージをDeno用に変換するレイヤーがあるんですけど、100%互換とは言いがたい。新しいプロジェクトなら問題ないんですが、既存コード移植は大変です。

Bun:モダンだけど若い

// Bun独自のAPIが多い。これはNode.js互換じゃない
const response = await fetch("https://api.example.com/users");
const data = await response.json();

// Bun固有の高速パーサー
import { parseQuery } from "bun";
const query = parseQuery("foo=bar&baz=qux"); // めっちゃ速い

Bunは「モダンなJavaScript実行環境」を目指してるんで、言語仕様が新しい。JSX・TypeScriptがビルトなしで動くのは本当に便利。開発体験は3つの中で一番気持ちいいです。

ただし、Node.jsとの互換性を重視してない機能が結構あるんですよ。npmパッケージも「Bun対応」を明記してるものだけ確実に動く。その点ではまだ若い。正直なところ、成熟度ではまだ一歩劣ります。

本番環境での落とし穴

ここが一番大事。本番で3つ並べたときに見えた現実です。

Node.js:運用資産が豊富

モニタリング・ロギング・デバッグツールの生態系が成熟してるんです。うちの本番環境はDatadogで監視してるんですけど、Node.js用のAPMプラグインはもう10年モノなんで、バグとか落とし穴も周知されてる。

あと、チームの知見が貯まってるんですよね。「あのバージョンのV8は接続プール数を多めにしないとダメ」みたいな、実務ベースのノウハウがある。これが本番トラブルを速く解決するカギになるんです。

Deno:本番での権限管理が光る

正直、Denoはセキュリティを重視する運用では最強。SOC2審査に向けて監査ログを整備してるんですけど、Denoのパーミッションモデルは監査の説明がめっちゃ楽なんですよ。

# Denoなら、起動時の権限で全部可視化される
deno run --allow-read=/data --allow-net=api.example.com server.ts

# CloudWatch Logsに記録される
# └─ 実行時刻: 2026-05-10T15:32:01Z
# └─ 権限: read:/data, net:api.example.com

Node.jsだと、アプリケーションレイヤーで全部実装しないといけない。その点、Denoは「OS的に制御してくれる」感じで、運用は楽です。監査時の説明もシンプルになるんですよね。

Bun:本番環境でまだ成長途上

率直に言うと、本番で急なバグに遭遇するリスクが高い。例えば、僕らが本番投入した直後に「特定条件でメモリリーク」みたいなissueが出てて、緊急パッチ待ちになったことがあるんですよ。

現時点(2026年5月)では、スタートアップレベルの小規模サービスなら全然大丈夫。ただし「3年は同じコードベース保守する」みたいなエンタープライズプロジェクトだと、ちょっと慎重になります。

あとは、本番環境のコンテナ化も考慮が必要。Node.js・Denoはどのコンテナランタイムでも問題ないんですけど、Bunはまだ「公式イメージがちょっと太い」という印象があります。Dockerイメージサイズも無視できない差が出るんですよ。

ランタイム選択フローチャート

実際にプロジェクトで判断してみた結果をまとめると、こんな感じで考えてみてください。

flowchart TD
    A[新規プロジェクト] --> B{何を優先する?}
    B -->|スピード・生態系| C[Node.js]
    B -->|セキュリティ・型安全| D[Deno]
    B -->|最高性能・モダン開発| E[Bun]
    
    C --> C1[Express/Fastify/Hono]
    C --> C2[npm生態系活用]
    C --> C3[本番資産が豊富]
    
    D --> D1[標準ライブラリ充実]
    D --> D2[権限管理が厳格]
    D --> D3[TypeScript一級市民]
    
    E --> E1[ビルドが高速]
    E --> E2[JSX直実行]
    E --> E3[小規模サービス向き]

実装パターンの向き不向き

各ランタイムがどんなプロジェクトに向いてるか、実装してわかったことを表にしてみます。

パターンNode.jsDenoBun
既存Node.jsプロジェクト×
新規・TypeScript統一
セキュリティが最優先
npm生態系に依存
小規模スタートアップ
大規模エンタープライズ×
API・バックエンド
CLI・ツール開発
リアルタイム・WebSocket
本番3年以上保守

まとめ

正直、「Node.jsが最強」と言うつもりはないんですよ。でも実務ベースで見ると、こういう判断になるんです。

Node.js は、既存資産がある、チーム知見がある、本番トラブルのノウハウが貯まってるなら、敢えて移行する理由は薄い。大規模チームなら尚更。「動いてるなら触るな」という原則が働くんですよね。

Deno は、セキュリティが必須要件、新規プロジェクト、TypeScript統一したいなら検討の価値あり。ただ、npm互換性を全面的に頼るプロジェクトは避ける方が無難です。標準ライブラリが充実してるから、そっちで何とかなることが多いんですよ。

Bun は、小規模チーム、新規サービス、開発体験優先なら試す価値あり。ただ本番環境は「1年後の成熟度を見守る」くらいのスタンスが良い。成長速度は本当に速いんで、半年後には話が変わってるかもしれません。

最後に、一つだけ言わせてもらうと——どのランタイムでも「デプロイ後の監視・ログ・アラート」の仕組みが無いと、本当に地獄ですよ。パフォーマンス比較より、まずそこから始める。うちはそれで何回も救われてます。実は選んだランタイムより、運用体制の方が重要なんですよね。

皆さんのチームはどれ選んでますか?いや、もう決まってるんですかね。それなら「なぜそれか」をもう一度確認してみるの、悪くないと思いますよ。

U

Untanbaby

ソフトウェアエンジニア|AWS / クラウドアーキテクチャ / DevOps

10年以上のIT実務経験をもとに、現場で使える技術情報を発信しています。 記事の誤りや改善点があればお問い合わせからお気軽にご連絡ください。

関連記事