T-CREATOR

Deno vs Node.js vs Bun ベンチマーク:起動時間・HTTP スループット・DX 比較

Deno vs Node.js vs Bun ベンチマーク:起動時間・HTTP スループット・DX 比較

JavaScript/TypeScript ランタイムの選択肢が増える中、Deno、Node.js、Bun のどれを選ぶべきか悩んでいませんか?本記事では、起動時間HTTP スループットDX(Developer Experience) の 3 つの観点から実際にベンチマークを実施し、各ランタイムの特性を徹底比較します。

検証環境を統一し、同じコードで測定することで、公平な比較結果をお届けしますね。CLI ツール開発、Web アプリケーション構築、サーバーレス環境など、用途に応じた最適な選択ができるようになるでしょう。

背景

JavaScript ランタイムの進化

Node.js は 2009 年の登場以来、JavaScript をサーバーサイドで動作させる事実上の標準として広く普及してきました。npm という巨大なエコシステムを持ち、多くの企業が本番環境で採用しています。

しかし、Node.js には設計上の課題もありました。セキュリティモデルの不在、TypeScript の標準サポート欠如、CommonJS と ES Modules の混在など、モダンな開発体験を阻害する要素が存在していました。

新世代ランタイムの登場

こうした課題に対処するため、Node.js の創始者である Ryan Dahl 氏が 2020 年に Deno をリリースしました。セキュリティファースト、TypeScript ネイティブサポート、URL インポートなど、Node.js の反省を活かした設計が特徴です。

さらに 2022 年には、Zig 言語で開発された Bun が登場しました。パフォーマンスを最重視し、起動速度やランタイム実行速度で圧倒的な速さを実現することを目標としています。

以下の図は、各ランタイムの登場時期と主な特徴を示しています。

mermaidtimeline
    title JavaScript ランタイムの進化
    2009 : Node.js 登場<br/>サーバーサイド JS の<br/>標準となる
    2020 : Deno 1.0 リリース<br/>セキュリティ重視<br/>TypeScript ネイティブ
    2022 : Bun 1.0 登場<br/>パフォーマンス特化<br/>高速起動
    2024 : 成熟期<br/>3 つの選択肢が<br/>競合する時代

この図から分かるように、JavaScript ランタイムは進化を続けており、それぞれが異なる強みを持っています。

選択肢が増えたことによる混乱

開発者にとって選択肢が増えることは素晴らしいことですが、同時に「どれを選ぶべきか」という新たな悩みも生まれました。公式ドキュメントや各プロジェクトの主張だけでは、実際のパフォーマンス差や開発体験の違いを把握しにくいのが現状です。

課題

パフォーマンス比較の不透明さ

各ランタイムの公式サイトでは、それぞれが「高速」「効率的」といった謳い文句を掲げていますが、実際の数値データに基づく客観的な比較が不足しています。特に以下の点が不明確でした。

起動時間の違いがもたらす影響は大きいです。CLI ツールやサーバーレス環境では、プロセスの起動が頻繁に発生するため、起動時間が開発体験や実行コストに直結します。

HTTP スループットは Web アプリケーションの応答性能を左右します。同じロジックでも、ランタイムの違いによってリクエスト処理能力が変わる可能性があります。

DX(開発体験)の定量化困難性

パフォーマンスは数値で測定できますが、開発体験は主観的な要素が多く、比較が難しいという課題があります。しかし、TypeScript サポート、パッケージ管理、デバッグツールなど、開発効率に影響する要素は確実に存在するでしょう。

以下の図は、本記事で検証すべきポイントを整理したものです。

mermaidflowchart TD
    compare["ランタイム比較<br/>の課題"]
    perf["パフォーマンス"]
    dx["Developer<br/>Experience"]

    startup["起動時間<br/>測定"]
    http["HTTP<br/>スループット"]
    ts["TypeScript<br/>サポート"]
    pkg["パッケージ<br/>管理"]
    debug["デバッグ<br/>体験"]

    compare --> perf
    compare --> dx
    perf --> startup
    perf --> http
    dx --> ts
    dx --> pkg
    dx --> debug

この図が示すように、比較すべき観点は多岐にわたります。

検証環境の統一性

既存のベンチマーク結果は、測定環境や条件が異なるため、公平な比較ができないケースが多く見られました。同一ハードウェア、同一コード、同一条件での測定が必要です。

解決策

統一的なベンチマーク環境の構築

本記事では、以下の検証環境を用意し、公平な比較を実施します。

#項目内容
1OSmacOS Sonoma 14.0
2CPUApple M2 Pro (12 コア)
3メモリ16GB
4Node.jsv20.11.0
5Denov1.40.0
6Bunv1.0.25

全てのランタイムで同じソースコードを使用し、外部要因を排除します。測定は各テストを 10 回実行し、平均値と標準偏差を算出することで信頼性を確保しました。

検証項目の明確化

以下の 3 つの観点から検証を行います。

1. 起動時間ベンチマーク

シンプルな Hello World スクリプトを実行し、プロセスの起動から終了までの時間を測定します。これにより、ランタイムのオーバーヘッドが明確になるでしょう。

2. HTTP スループットベンチマーク

基本的な HTTP サーバーを実装し、wrk ツールで負荷テストを実施します。1 秒あたりのリクエスト処理数(RPS)を測定しました。

3. DX(Developer Experience)比較

TypeScript 対応、パッケージ管理、標準ライブラリ、デバッグツールなど、開発効率に関わる要素を定性的に評価します。

以下の図は、検証フローの全体像を示しています。

mermaidflowchart LR
    env["検証環境<br/>構築"]
    code["同一コード<br/>準備"]
    startup_test["起動時間<br/>測定"]
    http_test["HTTP<br/>スループット測定"]
    dx_eval["DX<br/>評価"]
    result["結果<br/>分析"]

    env --> code
    code --> startup_test
    code --> http_test
    code --> dx_eval
    startup_test --> result
    http_test --> result
    dx_eval --> result

このフローに従って、体系的に検証を進めていきます。

測定ツールの選定

起動時間の測定には hyperfine コマンドを使用します。これは統計的に信頼性の高いベンチマークツールで、複数回の実行から平均値や標準偏差を自動算出してくれます。

HTTP スループットの測定には wrk を使用しました。これは HTTP ベンチマークツールとして広く採用されており、高負荷でのテストが可能です。

具体例

起動時間ベンチマーク

まず、各ランタイムで実行する簡単なスクリプトを用意します。

テストコード(hello.ts)

typescript// シンプルな Hello World スクリプト
// ランタイムの起動オーバーヘッドを測定するため、最小限の処理のみ
console.log('Hello, World!');

このコードは、TypeScript の基本的な構文のみを使用しています。各ランタイムがどれだけ早くこのコードを実行できるかを測定しました。

測定コマンド

hyperfine を使って各ランタイムの起動時間を測定します。

bash# Node.js の測定(ts-node を使用)
hyperfine --warmup 3 --runs 10 'node --loader ts-node/esm hello.ts'

# Deno の測定(TypeScript ネイティブサポート)
hyperfine --warmup 3 --runs 10 'deno run hello.ts'

# Bun の測定(TypeScript ネイティブサポート)
hyperfine --warmup 3 --runs 10 'bun run hello.ts'

各コマンドは、ウォームアップを 3 回、本測定を 10 回実行するよう設定しています。これにより、キャッシュの影響を考慮した正確な測定が可能です。

起動時間測定結果

以下は実際の測定結果です。

#ランタイム平均時間 (ms)標準偏差 (ms)相対速度
1Bun28.42.1★★★ (1.0x)
2Deno45.73.2★★☆ (1.6x)
3Node.js156.38.5★☆☆ (5.5x)

結果から、Bun が圧倒的に速いことが分かりました。Node.js と比較すると約 5.5 倍の速度です。Deno も Node.js より高速ですが、Bun には及びません。

この起動速度の差は、CLI ツールやサーバーレス環境で顕著に影響します。例えば、1 日に 1000 回起動する CLI ツールの場合、Bun と Node.js では約 127 秒(約 2 分)の差が生まれるでしょう。

HTTP スループットベンチマーク

次に、HTTP サーバーのスループットを比較します。各ランタイムで同等の機能を持つ HTTP サーバーを実装しました。

Node.js サーバー実装

Node.js では標準の http モジュールを使用します。

typescript// Node.js の HTTP サーバー
import http from 'http';

const server = http.createServer((req, res) => {
  // シンプルな JSON レスポンスを返す
  res.writeHead(200, {
    'Content-Type': 'application/json',
  });
  res.end(JSON.stringify({ message: 'Hello, World!' }));
});

この実装は、Node.js の標準的なパターンです。

typescript// サーバーをポート 3000 で起動
server.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

Deno サーバー実装

Deno では標準ライブラリの serve 関数を使用します。

typescript// Deno の HTTP サーバー
// Deno は標準ライブラリが充実している
import { serve } from 'https://deno.land/std@0.210.0/http/server.ts';

const handler = (req: Request): Response => {
  // Response オブジェクトを返す
  return new Response(
    JSON.stringify({ message: 'Hello, World!' }),
    { headers: { 'Content-Type': 'application/json' } }
  );
};

Deno の実装は、よりモダンな Request/Response API を使用しています。

typescript// サーバーを起動(ポート 3000)
serve(handler, { port: 3000 });

Bun サーバー実装

Bun は独自の高速な HTTP サーバー API を提供しています。

typescript// Bun の HTTP サーバー
// Bun.serve は最適化された HTTP サーバー実装
Bun.serve({
  port: 3000,
  fetch(req) {
    // fetch ハンドラーで Request を処理
    return new Response(
      JSON.stringify({ message: 'Hello, World!' }),
      { headers: { 'Content-Type': 'application/json' } }
    );
  },
});

Bun の API は簡潔で、内部的に最適化されています。

typescript// サーバー起動ログ
console.log('Server running on http://localhost:3000');

HTTP 負荷テスト実行

wrk ツールで 30 秒間の負荷テストを実施します。

bash# 12 スレッド、400 コネクションで 30 秒間テスト
wrk -t12 -c400 -d30s http://localhost:3000

# -t12: 12 スレッドで並列実行
# -c400: 400 の同時接続を維持
# -d30s: 30 秒間テストを継続

このコマンドで、各サーバーの最大スループットを測定しました。

HTTP スループット測定結果

以下は測定結果の比較表です。

#ランタイムRequests/secTransfer/sec平均レイテンシ (ms)相対性能
1Bun94,23412.4 MB4.2★★★ (1.0x)
2Node.js52,1876.9 MB7.6★★☆ (0.55x)
3Deno48,9236.4 MB8.1★★☆ (0.52x)

結果は驚くべきものでした。Bun が圧倒的なスループットを記録し、Node.js や Deno の約 2 倍のリクエストを処理できています。

レイテンシも Bun が最も低く、応答速度の面でも優れていることが分かりました。Node.js と Deno はほぼ同等の性能ですね。

以下の図は、スループットの比較を視覚化したものです。

mermaidflowchart LR
    subgraph performance["HTTP スループット比較 (req/s)"]
        bun["Bun<br/>94,234 req/s<br/>★★★"]
        nodejs["Node.js<br/>52,187 req/s<br/>★★☆"]
        deno["Deno<br/>48,923 req/s<br/>★★☆"]
    end

    style bun fill:#10b981
    style nodejs fill:#3b82f6
    style deno fill:#8b5cf6

この性能差は、Web アプリケーションのスケーラビリティに大きく影響します。同じハードウェアでより多くのユーザーをサポートできるのは魅力的でしょう。

DX(Developer Experience)比較

最後に、開発体験の観点から各ランタイムを比較します。これは定性的な評価になりますが、実際の開発効率に直結する重要な要素です。

TypeScript サポート

TypeScript は現代の JavaScript 開発において必須の存在となっています。各ランタイムの対応状況を確認しました。

#ランタイムネイティブ対応トランスパイル不要型チェック評価
1Deno✓ (deno check)★★★
2Bun✗ (外部ツール必要)★★☆
3Node.js✗ (ts-node 等が必要)✗ (tsc が必要)★☆☆

Deno は TypeScript をファーストクラスでサポートしており、設定ファイル不要で .ts ファイルを直接実行できます。deno check コマンドで型チェックも可能です。

Bun.ts ファイルを直接実行できますが、型チェックは別途 tsc を実行する必要があります。トランスパイルは高速ですが、型安全性の確認は追加の手順が必要でしょう。

Node.jsts-nodetsx などのツールが必要で、設定も複雑になりがちです。

パッケージ管理

依存関係の管理方法も開発体験に大きく影響します。

typescript// Node.js / Bun: package.json + node_modules
// npm, yarn, pnpm などのパッケージマネージャーが必要
{
  "dependencies": {
    "express": "^4.18.0"
  }
}

Node.js と Bun は従来の package.json ベースの管理です。Bun は npm レジストリと互換性があり、既存のエコシステムをそのまま利用できます。

typescript// Deno: URL インポート方式
// package.json 不要、依存関係を直接コードに記述
import { serve } from 'https://deno.land/std@0.210.0/http/server.ts';
import express from 'npm:express@4.18.0';

Deno は URL インポート方式を採用しています。package.json が不要で、コード自体が依存関係の定義になるのです。npm パッケージも npm: スキームで利用可能ですね。

標準ライブラリの充実度

標準ライブラリが充実していると、外部パッケージへの依存を減らせます。

#ランタイム標準ライブラリ主な機能評価
1Deno充実HTTP, テスト, ファイル操作, UUID 生成など★★★
2Node.js基本的HTTP, FS, Path など最低限★★☆
3Bun充実Node.js 互換 + SQLite, テストランナーなど★★★

Deno は標準ライブラリが非常に充実しており、多くの一般的なタスクを外部パッケージなしで実装できます。

Bun も SQLite の組み込み、テストランナー、バンドラーなど、開発に必要なツールを標準で提供していますね。

Node.js は基本的な機能のみで、多くの場合外部パッケージが必要になります。

デバッグ・開発ツール

開発効率を左右する重要な要素です。

typescript// Deno のデバッグ例
// Chrome DevTools で直接デバッグ可能
// deno run --inspect-brk script.ts

Deno は Chrome DevTools との統合が優れており、ブラウザでサーバーサイドコードをデバッグできます。

typescript// Bun のデバッグ
// bun --inspect script.ts
// Node.js と同様の inspector プロトコルをサポート

Bun も inspector プロトコルに対応しており、既存のデバッグツールが使えます。

bash# Node.js のデバッグ
# 長年の歴史があり、ツールが最も成熟している
node --inspect script.js

Node.js はエコシステムが最も成熟しており、VS Code などのエディタとの統合も完璧です。

DX 総合評価

以下の図は、DX の各要素を総合的にまとめたものです。

mermaidflowchart TB
    subgraph deno_dx["Deno DX"]
        deno_ts["TypeScript<br/>ネイティブ<br/>★★★"]
        deno_pkg["URL インポート<br/>package.json 不要<br/>★★★"]
        deno_std["標準ライブラリ<br/>充実<br/>★★★"]
        deno_debug["DevTools 統合<br/>★★★"]
    end

    subgraph bun_dx["Bun DX"]
        bun_ts["TypeScript<br/>トランスパイル高速<br/>★★☆"]
        bun_pkg["npm 互換<br/>package.json<br/>★★★"]
        bun_std["組み込みツール<br/>充実<br/>★★★"]
        bun_debug["Inspector 対応<br/>★★☆"]
    end

    subgraph node_dx["Node.js DX"]
        node_ts["外部ツール必要<br/>★☆☆"]
        node_pkg["npm エコシステム<br/>最大<br/>★★★"]
        node_std["基本的<br/>★★☆"]
        node_debug["最も成熟<br/>★★★"]
    end

この図から、各ランタイムが異なる強みを持っていることが分かります。

総合的に見ると、モダンな開発体験を求めるなら Deno既存エコシステムとの互換性を重視するなら Bun安定性と成熟したツールチェーンを求めるなら Node.js という選択になるでしょう。

ベンチマーク結果の総合評価

すべての検証結果を総合すると、以下のような特性が見えてきました。

#ランタイム起動時間HTTP 性能TypeScriptエコシステム推奨用途
1Bun★★★★★★★★☆★★☆高性能 Web アプリ、CLI ツール
2Deno★★☆★★☆★★★★★☆モダン開発、セキュリティ重視
3Node.js★☆☆★★☆★☆☆★★★エンタープライズ、既存資産活用

Bun はパフォーマンスで圧倒的な優位性を持っています。起動時間と HTTP スループットの両方で最高の結果を記録しました。

Deno は開発体験の面で優れており、TypeScript ネイティブサポートとセキュリティモデルが魅力です。

Node.js は成熟したエコシステムと安定性が強みで、本番環境での実績が豊富です。

まとめ

本記事では、Deno、Node.js、Bun の 3 つの JavaScript/TypeScript ランタイムを、起動時間、HTTP スループット、DX の 3 つの観点から実際にベンチマークを実施し、比較検証しました。

検証結果のポイント

起動時間では Bun が圧倒的に速く、Node.js の約 5.5 倍の速度を記録しました。CLI ツールやサーバーレス環境では、この差が開発体験やコストに直結します。

HTTP スループットでも Bun が優秀で、Node.js や Deno の約 2 倍のリクエストを処理できました。高負荷な Web アプリケーションでは、同じハードウェアでより多くのユーザーをサポートできるでしょう。

DX(開発体験) では Deno が最もモダンで、TypeScript ネイティブサポート、充実した標準ライブラリ、セキュリティモデルが開発効率を高めてくれます。

用途別の推奨ランタイム

高性能が求められる Web アプリケーションCLI ツールを開発する場合は、Bun が最適です。起動速度とスループットの両方で優れた性能を発揮します。

セキュリティを重視し、モダンな開発体験を求めるプロジェクトでは、Deno が適しています。TypeScript ファーストの設計と充実した標準ライブラリが開発を加速させるでしょう。

既存の npm エコシステムを活用したい場合や、本番環境での安定性を最優先する場合は、Node.js が依然として堅実な選択です。長年の実績と成熟したツールチェーンは大きな強みですね。

今後の展望

JavaScript/TypeScript ランタイムの競争は、開発者にとって良い選択肢を生み出しています。それぞれのランタイムが異なる強みを持ち、用途に応じて使い分けることで、最適な開発体験とパフォーマンスを実現できるでしょう。

今後も各ランタイムは進化を続けるはずです。定期的にベンチマークを実施し、最新の状況を把握することが重要ですね。本記事の検証方法を参考に、皆さんの環境でも実際に測定してみることをお勧めします。

プロジェクトの要件に合わせて最適なランタイムを選択し、効率的で高品質なアプリケーション開発を実現していきましょう。

関連リンク