あわせて読む: 検証計画書
Windows 11 の同一マシン上で、3 ランタイムの最新版を tools/ 配下に隔離配置し、11 項目のベンチマークと npm 互換性チェックを実施しました。
Bun 1.4.4 が総合スコア 84.8 点で最上位、Deno 2.9.8 が 66.0 点、Node.js 26.12.1 が 61.9 点でした。
ただしこの順位は「速さ」の重みが大きい配点によるもので、用途を絞ると結論は変わります。
npm 互換性は 8 パッケージすべてが 3 ランタイムで動作し、差がつきませんでした。
一方で LTS による長期サポートは Node.js だけが持っています。
計画書で用意した判断マトリクスを、実測値で埋めた結果です。総合スコアではなくこの表が本レポートの結論です。
| 用途 | 推奨 | 根拠(実測値) |
|---|---|---|
| 長期運用する業務 API サーバ | Node.js 26 | LTS 制度を持つのは Node.js だけで、26 系は 2026-10 に LTS 化予定。SQLite は最速(181.2 ms 対 Deno 314.1 ms)。HTTP の共通コード(node:http)では Bun に 1 割強譲るが、Deno の 1.47 倍(31,895 req/s)。 |
| 社内向け CLI ツール | Bun | 起動 20.1 ms(Node 50.8 ms の 2.5 倍速)。実行ファイル化は 0.7 秒で完了。出力サイズを最優先するなら Deno(76.7 MB 対 Bun 109.9 MB)。 |
| 使い捨てのスクリプト・自動化 | Bun | 起動・TypeScript 実行(61.3 ms)ともに最速で、書いてすぐ回す用途に効く。3 者とも設定なしで .ts が動いた。 |
| フロントエンドのビルド基盤 | Bun | テスト実行 46.7 ms(Node の 4.0 倍速)、バンドルとテストが本体に同梱。CI でキャッシュを効かせるのが主眼なら Deno(キャッシュ有インストール 0.9 秒)。 |
| 既存 Node.js プロジェクトの高速化 | Bun | npm パッケージ 8/8 が無修正で動作。CPU 処理 2.08 倍、テスト 4.03 倍、起動 2.53 倍、node:http のサーバも 1.12 倍速い。ただし SQLite は Node が速く(Bun は 1.13 倍遅い)、置き換えで遅くなる処理もある。 |
| 外部コードを実行するサンドボックス用途 | Deno | 権限が既定で拒否される唯一のランタイム。今回のスクリプトはすべて -A を明示しないと動かなかった。ファイル・ネットワーク・環境変数の粒度で許可を絞れる。 |
| 項目 | 内容 |
|---|---|
| OS | Windows 11 Home(build 26300) |
| CPU | Intel Core i7-11370H @ 3.30GHz(4 物理コア / 8 論理) |
| メモリ | 31.8 GB |
| 計測日 | 2026-10-25 |
| ストレージ | NVMe KIOXIA KXG60ZNV1T02 |
| 電源 | AC 接続・電源モード「最大パフォーマンス」(この機種に powercfg の高パフォーマンスプランは存在しない) |
| 計測ツール | hyperfine 1.20.0(プロセス単位)/ oha 1.16.0(HTTP 負荷) |
| ランタイム | バージョン | 位置づけ |
|---|---|---|
| Node.js | 26.12.1 | 主軸Current 系列。レポートの Node.js 代表値 |
| Node.js | 24.22.1 | 参考Active LTS (Krypton)。26 系との世代差を見るため併記 |
| Deno | 2.9.8 | 主軸 |
| Bun | 1.4.4 | 主軸 |
3 ランタイムはいずれもシステムにインストールせず、公式配布物をプロジェクト内 tools/ に展開して明示パスで呼び出しました。
Node.js と Deno は公式の SHA256 と一致することを確認済みです。システムにインストールされているランタイムは使っていません。
node:http 版と、Deno.serve / Bun.serve の固有 API 版を別項目として記録しました。片方だけを取り上げていません。docs/results/measurements.csv に残しています。--shell=none で実行し、起動時間に cmd.exe のコストを混ぜていません。| 項目 | 変更内容と理由 |
|---|---|
| B-05 の件数 | 1 万件 → 2000 件。1 ファイルあたり約 3.7 ms かかり、1 万件では 4 ランタイム × 10 回で 30 分を超えるため。Windows のファイル単位オーバーヘッドが支配的で、件数を増やしても分解能は上がりません。 |
| B-03 の試行 | 他項目のような 10 回反復ではなく、10 秒 × 50 接続の負荷試験を 1 回。この項目の指標は req/s であり、負荷試験の内部で十分な回数のリクエストが発生するためです。したがって B-03 には標準偏差がありません。 |
| Node.js 22 | 対象外にしました。工数を主軸(26 系)の精度に回す判断です。 |
| 互換性の見本 | ネイティブアドオンの見本を better-sqlite3 から bcrypt 6.0.0 に替えました。better-sqlite3 を版の指定なしで入れると、ビルド済みバイナリがまだ無い新しい版を引き、手元でのビルドに回って失敗したためです。bcrypt は Node-API で書かれ、バイナリを npm パッケージに同梱しているので、Node.js の版を上げても同じことは起きません。版も固定しました。依存の総量が減ったため、B-08 の数値は初回と比べられません。 |
| 計測コードの拡張子 | 12 本のうち 10 本を .mjs で書いています。TypeScript を優先する取り決めとは外れますが、計測済みの数値を守るためにそのままにしました。.ts に変えると型ストリップの処理が起動時に入り、B-01・B-02・B-09 の値がここに載っているものと変わります。拡張子を揃えるなら 11 項目すべてを測り直す必要があります。 |
プロセスを起動して終わるまでの時間を hyperfine で測った項目です。CLI ツールや使い捨てスクリプトでは、この時間がそのまま体感になります。
| 項目 | Node.js 26 | Deno | Bun | Node.js 24(参考) | 最速比 |
|---|---|---|---|---|---|
| B-01 空スクリプト起動 | 50.8 ms | 57.7 ms | 20.1 ms | 48.1 ms | Bun が 2.53 倍速 |
| B-02 依存込み起動 | 117.7 ms | 134.7 ms | 38.9 ms | 117.3 ms | Bun が 3.02 倍速 |
| B-09 TypeScript 実行 | 147.0 ms | 107.1 ms | 61.3 ms | 141.2 ms | Bun が 2.40 倍速 |
| B-11 テスト 200 件 | 188.2 ms | 136.7 ms | 46.7 ms | 204.1 ms | Bun が 4.03 倍速 |
.ts を投げる使い方では有利になります。tsconfig.json もトランスパイル手順も無しに .ts を直接実行できました。Node.js の型ストリップは消去可能な構文に限られるため、enum や namespace を使うコードでは差が出ます(今回はそれらを避けた共通コードで測定)。node:test 記法の 200 件を無修正で 200 件パスさせました。互換性は問題なく、差は純粋にランナーの速度です。10 秒間・50 同時接続で "Hello" を返し続けたときの毎秒リクエスト数です。共通の node:http 版と、各ランタイム固有 API 版を分けて測りました。
| サーバ実装 | req/s | p50 遅延 | p99 遅延 | 備考 |
|---|---|---|---|---|
Node.js 26 / node:http | 31,895 | 1.53 ms | 3.27 ms | Bun に 1.12 倍の差で 2 位 |
Node.js 24 / node:http | 26,487 | 1.80 ms | 4.04 ms | 参考値。26 が 1.20 倍速い |
Deno / node:http | 21,698 | 2.18 ms | 4.92 ms | 互換レイヤ経由 |
Bun / node:http | 35,643 | 1.36 ms | 2.66 ms | 共通コードでの最速 |
Deno / Deno.serve | 46,378 | 1.06 ms | 2.03 ms | 固有 API。共通版の 2.14 倍 |
Bun / Bun.serve | 40,239 | 1.22 ms | 2.33 ms | 固有 API。共通版の 1.13 倍 |
固有 API を使うかどうかで結論が変わります。
node:http のままなら Bun が最速で、Node.js 26 が 1.12 倍の差で続き、Deno は Node.js 26 より 3 割ほど遅れます。固有 API まで許すと Deno が最速になり、Bun を 15.3% 上回りました(p99 遅延も Deno が 0.3 ms 短い)。
注目すべきは Deno の伸び幅で、互換レイヤを捨てると 2.14 倍になりました。Deno の node:http は互換のためのラッパで、性能を出す経路ではないことがはっきり出ています。
| ランタイム | 合計 | parse | 変換 | stringify | heap 使用量 |
|---|---|---|---|---|---|
| Node.js 26 | 80.1 ms | 57.4 ms | 9.5 ms | 11.6 ms | 41.8 MB |
| Node.js 24 | 84.3 ms | 59.9 ms | 8.3 ms | 16.8 ms | 61.7 MB |
| Deno | 84.6 ms | 55.9 ms | 16.7 ms | 10.8 ms | 60.3 MB |
| Bun | 62.2 ms | 38.0 ms | 12.2 ms | 10.4 ms | 39.0 MB |
合計では Bun が最速で、Node.js 26 の 1.29 倍です。差の大半は JSON.parse(Bun 38.0 ms 対 Node.js 26 57.4 ms)から来ています。
メモリ使用量は Bun(39.0 MB)と Node.js 26(41.8 MB)が小さく、Node.js 24・Deno は 60 MB 台でした。Node.js 24 → 26 で heap が 61.7 MB → 41.8 MB に減っているのは、
この検証で見えた 26 系の明確な改善点です。
| ランタイム | 合計 | 書き込み | 読み込み | 一覧 | 削除 |
|---|---|---|---|---|---|
| Node.js 26 | 2,535.8 ms | 1,883.1 ms | 210.6 ms | 1.2 ms | 414.9 ms |
| Node.js 24 | 2,001.4 ms | 1,511.1 ms | 172.0 ms | 1.2 ms | 308.7 ms |
| Deno | 2,243.8 ms | 1,642.6 ms | 209.5 ms | 4.7 ms | 381.4 ms |
| Bun | 1,991.6 ms | 1,489.3 ms | 171.9 ms | 1.0 ms | 334.7 ms |
この項目はランタイムの差より揺れの方が大きく出ます。 合計の最速は Bun ですが、Node.js 24 との差は 0.5% しかありません。 最遅の Node.js 26 は 1.27 倍遅く出ましたが、変動係数が 17.6% と大きく(10 回の幅は 1,790〜3,266 ms)、ほかの 3 者は 5〜10% でした。 1 ファイルあたり約 1 ms を Windows のファイル操作コストが占めており、Node.js 26 の遅れがランタイムの性質かどうかは、この 1 回の計測からは決められません。
| ランタイム | 合計 | 数値ループ | 文字列処理 | 配列ソート |
|---|---|---|---|---|
| Node.js 26 | 724.7 ms | 60.7 ms | 63.3 ms | 592.2 ms |
| Node.js 24 | 646.3 ms | 56.8 ms | 62.7 ms | 519.5 ms |
| Deno | 636.1 ms | 54.9 ms | 57.8 ms | 521.7 ms |
| Bun | 348.3 ms | 53.3 ms | 38.8 ms | 249.6 ms |
合計 2.08 倍(対 Node.js 26)という Bun の優位は、ほぼ配列ソートの 1 点から来ています(249.6 ms 対 Node.js 26 592.2 ms)。
100 万要素の Array.prototype.sort で JavaScriptCore が V8 の 2 倍以上速く、これが合計の差を作っています。
数値ループは 4 者とも 53〜61 ms で、差は 15% 以内でした。「Bun は CPU 処理が全般に速い」と一般化すると誤ります。
なお Node.js 26 はソートで 24 より 14% 遅く、この項目では 4 者の最下位でした。
| ランタイム | 合計 | 一括 INSERT | 集計クエリ | 点参照 2 万回 |
|---|---|---|---|---|
| Node.js 26 | 181.2 ms | 138.5 ms | 21.7 ms | 20.7 ms |
| Node.js 24 | 198.7 ms | 148.8 ms | 25.3 ms | 24.7 ms |
| Deno | 314.1 ms | 252.3 ms | 33.5 ms | 31.5 ms |
| Bun | 205.5 ms | 164.6 ms | 27.0 ms | 13.3 ms |
Node.js 26 が合計で最速です。 3 ランタイムすべてが node:sqlite を持っており、同じコードが無修正で動きました。
Bun は点参照で最速ながら合計では 1.13 倍の差で 2 位、Deno は INSERT で Node.js 26 の 1.82 倍遅く、合計でも 1.73 倍遅れました。DB アクセスが中心のワークロードでは、起動やソートの速さが結論を決めないことが分かります。
性質を混ぜた 8 パッケージ(純 JS 2・HTTP フレームワーク・DB ドライバ・ビルドツール・CLI・ネイティブアドオン 2)を、
同一の package.json から各パッケージマネージャでインストールした時間です。
| コマンド | クリーン | キャッシュ有 | node_modules | lock ファイル | postinstall スクリプト |
|---|---|---|---|---|---|
npm install | 16.8 秒 | 8.4 秒 | 2,285 件 / 51.4 MB | package-lock.json | 既定で実行 |
deno install | 7.7 秒 | 0.9 秒 | 2,380 件 / 51.4 MB | deno.lock | --allow-scripts で明示許可 |
bun install | 12.4 秒 | 6.7 秒 | 2,278 件 / 51.4 MB | bun.lock | 既定でブロック(trustedDependencies が必要) |
キャッシュが効いたときの差が極端です。 deno install の 0.9 秒に対し bun install は 6.7 秒、npm install は 8.4 秒。
Deno はグローバルキャッシュから node_modules を組み立て直すだけで済む設計になっており、この条件では 7〜10 倍の差がつきました。
一方クリーン(キャッシュもロックも無い)状態では 7.7〜16.8 秒に収まり、ネットワーク待ちが支配的になって差は 2.2 倍まで縮みます。
生成される node_modules はどれも 51.4 MB・2,300 件前後でほぼ同じでした。
bun install が postinstall を既定でブロックしても完走したのは、今回の対象のネイティブアドオンがバイナリを配る方式だったためです。
sharp は OS ごとの別パッケージを optionalDependencies で、bcrypt はパッケージへの同梱で配っています。ソースからのビルドが必要なパッケージでは結果が変わります。
各パッケージマネージャが作った node_modules に対し、対応するランタイムで import と主要エクスポートの存在確認を行いました。
| パッケージ | 分類 | Node.js 26 | Node.js 24 | Deno | Bun |
|---|---|---|---|---|---|
| zod | 純 JS ライブラリ | OK | OK | OK | OK |
| dayjs | 純 JS ライブラリ | OK | OK | OK | OK |
| express | HTTP フレームワーク | OK | OK | OK | OK |
| pg | DB ドライバ | OK | OK | OK | OK |
| esbuild | ビルドツール(ネイティブバイナリ同梱) | OK | OK | OK | OK |
| prettier | CLI ツール(bin エントリあり) | OK | OK | OK | OK |
| sharp | ネイティブアドオン(プリビルド配布) | OK | OK | OK | OK |
| bcrypt | ネイティブアドオン(Node-API・同梱バイナリ) | OK | OK | OK | OK |
| 成功率 | — | 8/8 | 8/8 | 8/8 | 8/8 |
package.json でこのチェックをやり直すのが、最も確実な確認方法です。
依存を持たない 1 ファイルの CLI を、実行ファイルに固めた結果です。生成物は実際に起動して期待した出力が出ることを確認しています。
| ランタイム | 方法 | 所要時間 | 出力サイズ | 動作 | 手順の重さ |
|---|---|---|---|---|---|
| Bun | bun build --compile | 0.7 秒 | 109.9 MB | OK | 1 コマンド |
| Deno | deno compile | 9.6 秒 | 76.7 MB | OK | 1 コマンド |
| Node.js 26 | SEA(--experimental-sea-config + postject) | 14.4 秒 | 100.6 MB | OK | 3 段階。postject を npm から取得する必要あり |
3 者すべて動く実行ファイルを作れましたが、手数が違います。Bun と Deno は 1 コマンドで完結、Node.js は
blob 生成 → node.exe の複製 → postject による注入の 3 段階で、しかも postject を npm から入れる必要があります。
14.4 秒のうち大半はこの npm インストールです。出力サイズは Deno が最小(76.7 MB)、Bun が最大(109.9 MB)でした。
前回(Deno 2.9.7・Bun 1.4.3)と比べて動いた値が 2 つあります。deno compile は 2.0 秒から 9.6 秒に延び、Bun の出力は 91.9 MB から 109.9 MB に増えました。
どちらも原因は確かめていません。Deno は版を上げた直後の 1 回目の計測なので、実行ファイルの土台をダウンロードする時間が入った可能性があります(未確認)。
npm error Tracker "idealTree" already exists で失敗しました。作業ディレクトリに package.json を置いていなかったため
npm が親ディレクトリを探索したことが原因で、Node.js の制約ではありません。package.json を置いて再実行し成功しています。
計測harnessの不備をランタイムの欠点として記録しないよう、失敗はすべて原因を切り分けました。
| 機能 | Node.js 26 | Deno 2.9.8 | Bun 1.4.4 |
|---|---|---|---|
| TypeScript の直接実行 | あり(型ストリップ・消去可能構文のみ) | あり(型チェックも可) | あり |
| テストランナー | あり(node --test) | あり(deno test) | あり(bun test) |
node:test 記法の実行 | 200/200 パス | 200/200 パス | 200/200 パス |
| フォーマッタ / リンタ | なし | あり(deno fmt / deno lint) | あり(bun fmt) |
| バンドラ | なし | あり(deno bundle) | あり(bun build) |
| 単一実行ファイル化 | あり(要 postject) | あり | あり |
| SQLite | あり(node:sqlite) | あり(node:sqlite) | あり(node:sqlite / bun:sqlite) |
| 権限モデル | なし(全許可) | あり(既定で拒否) | なし(全許可) |
| LTS による長期サポート | あり | なし | なし |
Deno の権限モデルは今回の検証で実際に体感しました。-A(全許可)を付けないと、
ファイル読み込み・環境変数参照・ポート待ち受けのいずれもエラーになります。手間ではありますが、
外部から持ち込んだスクリプトを走らせる場面ではこの既定拒否が他 2 者に無い価値になります。
定量項目は「各項目の最良値を 100 とした相対値」を軸内で平均、定性項目は 5 段階を 100 点満点に換算した値です。重みは計画時に確定させたものを変更していません。
| ランタイム | 総合スコア | 最も強い軸 | 最も弱い軸 |
|---|---|---|---|
| Bun 1.4.4 | 84.8 | 起動性能・実行性能・TypeScript・ツールチェーン(すべて 100 前後) | パッケージ管理 13.1/運用・サポート 40.0 |
| Deno 2.9.8 | 66.0 | パッケージ管理 100.0/開発体験 100.0 | ツールチェーン 20.7/起動性能 31.8 |
| Node.js 26.12.1 | 61.9 | 運用・サポート 100.0/Windows 対応 100.0/実行性能 78.8 | パッケージ管理 10.3/ツールチェーン 14.8 |
| Node.js 24.22.1(参考) | 63.0 | 26 系とほぼ同じ | 26 系とほぼ同じ(ツールチェーンは 22.9。下の注意 3 を参照) |
node:http)のみを入れています。
固有 API を使う前提なら Deno の実行性能スコアは上がります。
同じ計測を後日やり直せます。tools/ のバイナリと src/bench/fixtures/ のテストデータはリポジトリに含めず、スクリプトから再生成します。
# Windows PowerShell 5.1・pwsh 7 のどちらでも動く
# 1. ランタイムと計測ツールを tools/ に配置(SHA256 検証つき)
src/scripts/10_setup_runtimes/setup-runtimes.ps1
# 2. ベンチ本体(項目を分けて実行し、-Append で結果をマージできる)
src/scripts/20_run_bench/run-bench.ps1 -Runs 10 -Warmup 3 -Only B-01,B-02,B-09,B-11
src/scripts/20_run_bench/run-bench.ps1 -Runs 10 -Warmup 3 -FileCount 2000 -Only B-04,B-05,B-06,B-07 -Append
src/scripts/20_run_bench/run-bench.ps1 -Only B-03 -HttpSeconds 10 -HttpConnections 50 -Append
# 3. 依存インストールと npm 互換性
src/scripts/30_run_install_bench/run-install-bench.ps1
# 4. 単一実行ファイル化
src/scripts/40_run_compile_bench/run-compile-bench.ps1
# 5. 集計(定性評価は docs/results/qualitative.json を読む)
src/scripts/50_build_report/build-report.ps1
| 成果物 | 内容 |
|---|---|
docs/results/env.txt | 検証環境・版数・バイナリの SHA256 |
docs/results/measurements.csv | 項目 × ランタイムの中央値・最小・最大・標準偏差・変動係数 |
docs/results/summary.json | 相対スコア・評価軸スコア・総合スコアを含む集計結果 |
docs/results/qualitative.json | 定性評価のスコアと、その根拠にした実測値 |
docs/results/raw/ | hyperfine・oha の生出力、インストールログ、互換性チェックの生結果 |