DenoとBunの比較は、2026年10月に前提が変わりました。10月9日にDenoのチームがCloudflareへ合流し、Denoランタイムの開発は1年間の保守のあとで終わると発表されたためです。この記事では、Deno・Bun・Node.jsの版と保守期限、TypeScriptの実行範囲、Node.js互換、権限モデルを公式ドキュメントで比べます。そのうえで、DenoのコードをBunかNode.jsへ移す設定とコード、受託開発でどちらを選ぶかの条件を示します。
まとめ:Deno終了後の新規案件はNode.js 26を既定にしBunは条件付きで選ぶ
新しく作るシステムの実行基盤にDenoを選ぶ理由は、もうありません。公式の保守は2027年10月ごろまでで、その後は引き継ぐ開発者が現れない限り修正が止まります。
移行先の第一候補はNode.js 26です。10月28日にLTSへ入り、2029年4月末まで保守される予定が公表されています。Bunは起動の速さと1つの実行ファイルで完結する手軽さが強みで、社内ツールやCI、運用を自社で持つ小規模なAPIに向きます。APMやネイティブアドオンに頼る案件、5年規模の保守を請ける案件ではBunを選びません。
Denoで書いたコードは、Web標準のRequestとResponseで書いた部分ならほぼそのまま動きます。書き換えるのはDeno.で始まるAPIの呼び出しと、deno.jsonの依存の書き方です。
Deno・Bun・Node.jsの2026年10月時点の版と開発元・保守期限の比較
性能より先に、誰がいつまで直すのかを確かめます。受託で納めるシステムは、ランタイムの保守期限より長く動くことが珍しくないからです。
3ランタイムの最新版・開発元・保守期限を並べた2026年10月の一覧表
| 項目 | Deno | Bun | Node.js |
|---|---|---|---|
| 最新版(10月25日時点) | 2.9.8(10月21日) | 1.4.4(10月22日) | 26.12.1(10月21日) |
| 開発元 | DenoチームはCloudflareへ合流 | Anthropic傘下の同じチーム | OpenJS Foundation傘下 |
| 保守の見通し | 月次の修正版を1年出したあと開発終了 | LTSの制度なし | 26系は2029年4月30日まで |
| JavaScriptエンジン | V8 | JavaScriptCore | V8 |
版と日付はDenoのリリース一覧とBunのリリース一覧で確かめた値です。Bunだけエンジンが違う点は、プロファイラや監視ツールの対応に響きます。仕組みはBunがJavaScriptCoreで動く仕組みとNode.jsとの実行差で解説しています。
Deno公式ブログが示した1年保守と開発終了・JSR継続の範囲
Denoの公式ブログ「Deno is joining Cloudflare」は、ランタイムについて「バグ修正とセキュリティ修正を含む月次リリースで、あと1年サポートする」「その1年のあとで開発を終える」と書いています。コードはオープンソースのまま残り、開発を続けたい人を歓迎するとしています。
パッケージレジストリのJSRは運用を続け、基盤をCloudflareへ移します。Cloudflare側の発表も同じ10月9日付です。ホスティングのDeno Deployは6か月で停止するため、そちらを使っている場合の手順はDeno Deploy終了とCloudflare Workersへの移行手順にまとめました。
Bunの開発元Anthropic傘下入りとMITライセンス継続の意味
Bunは2025年12月2日にAnthropicへの合流を発表しています。発表では、BunはオープンソースでMITライセンスのまま、同じチームが開発を続けるとされました。Claude Codeなどの基盤として使われることが、投資の理由として挙げられています。
開発の資金面は安定した一方で、LTSにあたる長期保守の版は今も用意されていません。版を上げ続ける運用ができる案件かどうかが、Bunを選べるかの分かれ目です。
Node.js 26は10月28日にLTS入りし2029年4月末まで保守される予定
Node.jsのリリース計画では、26系は2026年10月28日にLTSとなり、2027年10月20日から保守期間に移って、2029年4月30日に終了します。現行LTSの24系は2028年4月30日までです。
今から作り始めて2027年に納める案件なら、26系を選べば納品後2年ほどは修正が届きます。26系の変更点と24系からの上げ方はNode.js 26の新機能と破壊的変更・LTS移行日を参照してください。
TypeScript実行・Node.js互換・権限モデルで比べる3ランタイムの実装差
Denoから移るときに差が出やすいのは、この3点です。Denoで当たり前だった動きが、移行先では設定やツールの追加を要します。
TypeScriptの直接実行でNode.jsだけenumとpathsが動かない違い
3つとも.tsファイルを変換なしで実行できます。ただし範囲は同じではありません。
| 観点 | Deno | Bun | Node.js 26 |
|---|---|---|---|
| 実行時の型チェック | しない(--checkで有効) |
しない | しない |
| enum・実体を持つnamespace | 動く | 動く | エラー |
| tsconfigのpaths | deno.jsonのimportsで代替 | 読む | 読まない |
| 型チェックの手段 | deno check |
tsc --noEmit |
tsc --noEmit |
Node.jsのTypeScriptのドキュメントによると、型を消して実行する機能は25.2.0と24.12.0で安定版になりました。消すだけで変換はしないため、enum、実体を持つnamespace、デコレーター、.tsxは動きません。変換を有効にする--experimental-transform-typesは26.0.0で削除されています。DenoのTypeScriptのドキュメントはenumなども追加の指定なしで動くとしており、Denoのコードをそのままnodeで動かすと、ここが実行の停止箇所です。BunはTypeScriptを変換して実行し、Bunのドキュメントはbun initが作るtsconfig.jsonの推奨値を示しています。
Node.jsへ移す場合、事前に次のコマンドでenumと実体を持つnamespaceの有無を調べると、書き換えの量が見積もれます。
grep -rnE "^\s*(export\s+)?(const\s+)?enum\s|^\s*(export\s+)?namespace\s" src/ --include=*.ts
Node.js互換の到達点とBunのnode:v8・perf_hooksの部分実装
DenoのNode・npm互換のドキュメントは、Deno 2.8の時点でNode.js自身のテストスイートの75%超が通るとしています。BunのNode.js互換の一覧はNode.js v26を対象に、Node.jsで動いてBunで動かないパッケージはBunのバグとみなす方針です。
Bunで実務に響くのは、監視とマルチプロセスの部分です。
node:perf_hooks:gc・dns・resourceのエントリを出さず、eventLoopUtilization()は常に0を返すnode:v8:ヒープスナップショットは取れるが、プロファイリングやSerializerは未実装node:async_hooks:AsyncLocalStorageは動くが、createHookはスタブnode:cluster:プロセス間のHTTP負荷分散はLinuxだけ
APMのエージェントはこれらに触れるものが多く、入れても数値が出ないまま本番へ出る事故になります。1.4での互換の伸び方はBun 1.4のRust移植と1.3からの移行で変わる挙動で詳しく扱っています。
Denoの権限フラグとNode.jsのPermission Modelの守備範囲の差
Denoのセキュリティのドキュメントのとおり、Denoは指定しない限りファイル・ネットワーク・環境変数に触れません。Node.jsにもPermission Modelがあり、23.5.0と22.13.0で安定版になりました。同じ制限を書くと次のようになります。
# Deno:ポート8000での待ち受けと環境変数DATABASE_URLだけを許可
deno run --allow-net=0.0.0.0:8000 --allow-env=DATABASE_URL main.ts
# Node.js:権限モデルを有効にし、読み取りを./configだけに絞る
node --permission --allow-fs-read=./config --allow-net main.ts
違いは2つあります。Node.jsのドキュメントは、この仕組みを悪意あるコードを防ぐサンドボックスではなく、信頼したコードの事故を防ぐ「シートベルト」だと明記しています。また環境変数の読み取りは制限の対象外です。BunはNode.jsと同じく、既定で権限を絞らずに動きます。Denoの権限設計に頼っていたシステムは、移行先ではコンテナの読み取り専用ファイルシステムや外向き通信の制限で同じ守りを作り直します。
起動速度とパッケージ導入の公称値を受託案件の判断に使う読み方
比較記事でよく見る速度の差は、条件を落とすと判断を誤らせます。公式の数字と、その前提だけを見ます。
起動5.1ミリ秒対Node.js 26の27.2ミリ秒という公称値の前提
Bun 1.4の公式ブログでは、Linuxでhello.jsを実行したときの起動がBun 1.4で5.1ミリ秒、Node.js 26で27.2ミリ秒でした。最大メモリは14.6MBと44.5MBです。Denoはこの比較に入っていません。
差が効くのは、短いプロセスを何度も起こす場面です。CIのスクリプト、CLIツール、リクエストごとに起動するサーバーレスがこれに当たります。常駐するAPIサーバーでは起動は1回きりで、より長いのは依存の読み込みやデータベースの待ち時間です。Node.jsのまま起動を縮める方法もあり、node_compile_cacheで起動を約45%短縮する設定を先に試す価値があります。
ネイティブアドオンとinstallスクリプトの扱いで変わる導入の手間
依存のインストール時に走るスクリプトの扱いは3つで異なります。Bunのライフサイクルスクリプトのドキュメントによると、Bunは許可リストにあるパッケージのスクリプトしか実行しません。package.jsonのtrustedDependenciesに書くと許可できますが、書いた時点で既定のリストは置き換わります。Denoも既定では実行せず、個別の許可に使う指定はdeno install --allow-scripts=npm:パッケージ名です。npmは既定で実行します。
sharpやbcryptのようにビルド済みバイナリを取りに行くパッケージは、この設定が漏れると実行時に初めて失敗します。移行の検証では、ネイティブアドオンを使うパッケージを先に一覧にしておくと手戻りが減ります。
DenoのコードをBunまたはNode.jsへ移す置き換え手順とコード例
ここからは作業です。Honoで書いたAPIを例に、1つのアプリを3つのランタイムで動かせる形に整えます。
deno.jsonのimportsとtasksをpackage.jsonへ移す設定例
移行前のdeno.jsonが次のような内容だとします。
{
"tasks": {
"dev": "deno run --watch --allow-net --allow-env main.ts"
},
"imports": {
"hono": "npm:hono@^4",
"@std/assert": "jsr:@std/assert@^1"
}
}
npm:の依存はそのままpackage.jsonへ移します。jsr:の依存は、JSRのnpm互換のドキュメントにあるnpx jsr addで追加すると、npm:@jsr/std__assertの形の別名で登録されます。
npx jsr add @std/assert
{
"type": "module",
"scripts": {
"dev:bun": "bun --watch main.bun.ts",
"dev:node": "node --watch main.node.ts"
},
"dependencies": {
"hono": "^4",
"@hono/node-server": "^1",
"@std/assert": "npm:@jsr/std__assert@^1"
}
}
npx jsr addはロックファイルから使っているパッケージマネージャーを判定し、.npmrcに@jsr:registry=https://npm.jsr.ioを書き込みます。Bunもこの.npmrcを読むため、bun installで同じ依存が入ります。
Deno.serveのHonoアプリをBun.serveとNode.jsへ移す3つの入口
アプリ本体をapp.tsに切り出し、ランタイムごとの入口ファイルを分けます。本体にはランタイム固有のAPIを書きません。
// app.ts(3ランタイム共通)
import { Hono } from "hono";
export const app = new Hono();
app.get("/health", (c) => c.text("ok"));
app.get("/hello", (c) => c.json({ greeting: process.env.GREETING ?? "hello" }));
// main.deno.ts(移行前と同じ動き)
import { app } from "./app.ts";
Deno.serve({ port: 8000 }, app.fetch);
// main.bun.ts(Bunはfetchを持つオブジェクトのexport defaultで起動する)
import { app } from "./app.ts";
export default { port: 8000, fetch: app.fetch };
// main.node.ts(Node.jsは@hono/node-serverで受ける)
import { serve } from "@hono/node-server";
import { app } from "./app.ts";
serve({ fetch: app.fetch, port: 8000 });
入口の書き方はHonoのBun向け手順とNode.js向け手順に沿っています。process.envはDenoでもNode.js互換として読めるため、本体を共通にできます。Node.jsで.tsを直接動かすときは、importの拡張子を省かずに書き、型だけの読み込みにはimport typeを付けてください。型を消したあとに存在しない名前を読もうとして、起動時に止まります。
Deno.env・Deno.readTextFileなどDeno名前空間APIの移行表
| Denoでの書き方 | Bun | Node.js |
|---|---|---|
Deno.env.get("X") |
process.env.XまたはBun.env.X |
process.env.X |
Deno.readTextFile(p) |
Bun.file(p).text() |
readFile(p, "utf8") |
Deno.args |
process.argv.slice(2) |
process.argv.slice(2) |
Deno.Command |
Bun.spawn |
spawn(node:child_process) |
deno testと@std/assert |
bun test |
node --testとnode:assert |
Node.jsのreadFileとspawnは、それぞれnode:fs/promisesとnode:child_processから読み込みます。BunにもNode.jsにも寄せられる書き方を選ぶなら、右端の列にそろえるのが安全です。Bun固有のAPIに寄せた部分は、後でNode.jsへ戻すときにもう一度書き換えが要ります。対象の洗い出しにはgrep -rn "Deno\." src/で呼び出しを全件拾い、件数で工数を見積もります。
受託開発でBunとNode.jsを採用する条件と見送る場面の判断基準
ここまでの比較を、案件の条件に当てはめて結論を出します。
Node.js 26 LTSを既定にする長期保守・監査・APM前提の受託案件
次のどれかに当てはまる案件は、Node.js 26で組みます。
- 納品後に3年以上の保守を請ける(LTSの終了日を契約の前提に書ける)
- DatadogやNew RelicなどのAPMで性能を監視する
- sharp・bcrypt・データベースドライバーなどのネイティブアドオンに依存する
- 金融・公共など、第三者の監査でランタイムの保守体制を問われる
BunのLTSの不在とnode:perf_hooksの部分実装は、どれも運用に入ってから効いてくる差です。迷う案件はNode.jsを選び、速度が要る箇所だけを後から見直すほうが総額は下がります。実行基盤の選定を含めて相談したい場合は、業務用・Webアプリ開発で対応範囲を確認できます。
Bunを選んでよい社内ツール・CI・単一バイナリ配布の3条件
Bunを選んでよいのは、次の3つがそろうときです。運用を自社で持ち、ランタイムの版を自分たちで上げ下げできること。ネイティブアドオンに頼らないこと。監視がHTTPのメトリクスとログで足りること。
この条件なら、ランタイム・パッケージマネージャー・テストランナー・バンドラーが1つの実行ファイルにまとまる利点が効きます。CIのイメージが小さくなり、bun build --compileで社内ツールを1ファイルとして配布することも可能です。インストールと基本のコマンドはBunのインストールとbun installなどの使い方で確認できます。
Denoを新規案件で選ばない理由と既存Denoコードを移す期限の目安
Denoは2027年10月ごろに公式の修正が止まる見込みです。インターネットに公開するサーバーで、修正の出ないランタイムを動かし続けるのは避けます。新規の案件では選びません。
既存のDenoのコードは、2027年の夏までに移し終える計画にする方針です。CLIや社内スクリプトのように影響が小さいものから先に移し、Deno KVやDeno Deployを使うものは期限の早いDeploy側を優先します。Deno環境を移行まで保つ手順はDenoとFreshの開発環境・権限設計・LTS選定にあります。
Deno・Bun・Node.jsの選定とDenoからの移行についてよくある質問
2026年10月25日時点の公式情報をもとに答えます。
DenoとBunはどちらが速いですか?
Bunの公式ブログは、Linuxでの起動がBun 1.4で5.1ミリ秒、Node.js 26で27.2ミリ秒と公表していますが、Denoとの公式比較はありません。第三者のベンチマークは条件がそろっておらず、数値をそのまま案件に当てはめられません。常駐するAPIサーバーでは起動の差はほとんど効かないため、自分の処理で同じ条件の計測をしてから判断してください。
Denoはもう使えなくなりますか?
すぐには使えなくなりません。Denoの公式ブログによると、今後1年間はバグ修正とセキュリティ修正を含む月次リリースが出ます。その後はDenoチームとしての開発が終わり、コードはオープンソースとして残ります。手元で動いているDenoのプログラムが急に止まるわけではありませんが、2027年秋以降は修正が届かない前提で移行を計画してください。
BunはNode.jsの代わりとしてそのまま使えますか?
多くのnpmパッケージは動きますが、完全な代わりではありません。BunのNode.js互換の一覧には、node:v8のプロファイリングやnode:perf_hooksの一部のエントリ、node:tlsのOCSPステープリングなどが未対応と書かれています。APMやプロファイラを使うシステム、ネイティブアドオンに頼るシステムは、移す前に依存が触れるモジュールを一覧で確認してください。
DenoのTypeScriptコードはNode.jsでそのまま動きますか?
型の注釈を消すだけで動く書き方なら動きます。Node.js 26は.tsを直接実行できますが、型を消すだけで変換はしません。enum、実体を持つnamespace、デコレーター、.tsxはエラーになり、tsconfigのpathsも読みません。該当する箇所を書き換えるか、tsxなどの変換ツールを挟む必要があります。Bunはこれらを変換して実行できます。
JSRのパッケージはBunやNode.jsでも使えますか?
使えます。JSRは運用を続け、基盤はCloudflareへ移るという発表内容です。BunとNode.jsではnpx jsr add @scope/nameで追加すると、npm:@jsr/scope__nameという別名でpackage.jsonに登録され、.npmrcにJSRの配布先が書き込まれます。pnpm 10.9以降とYarn 4.9以降はjsr:の指定を直接扱えます。
関連記事
- Deno Deploy終了と移行手順:Cloudflare WorkersへのコードとKV・cronの移し方:Deno Deployで動かしているアプリの移し先と手順。
- Bun 1.4とは?Rust移植の実態と1.4.3までの変更点・1.3からの移行で変わる挙動を実測:移行先にBunを選ぶときの版ごとの差。
- Bunランタイムとは?JavaScriptCoreで動く仕組みとNode.jsとの実行差・版の固定方法:エンジンの違いと版の固定手順。
- Bunとは?読み方とbrew・curlでのインストール、bun install・check・fmtの使い方:Bunの導入と基本のコマンド。
- Node.js 26の新機能と破壊的変更・LTS移行日|24からの移行手順:移行先にNode.js 26を選ぶときの変更点。