Deno 1 時代の「Node.js と別世界」だった Deno が、Deno 2(2024 年 10 月)で完全に姿を変えました。package.json も node_modules もそのまま使え、npm: / node: 指定子で既存エコシステムを取り込みつつ、TypeScript ファースト・Web 標準 API・Permission System・JSRという Deno の強みはそのまま維持。Node から Deno への移行コストが一気に下がりました。
2025 年末の Deno 2.6 では dx コマンド(npx 代替)・deno audit(CVE スキャン)・tsgo による型チェック 2 倍高速化が、2026 年初頭の Deno 2.7 では Temporal API 安定化と Windows ARM 対応が入り、日常使いのランタイムとして完成度を上げています。
この記事では 2026 年 4 月時点の Deno 2.7 系を前提に、Node/npm 互換・deno install / add / remove・JSR・dx・Workspaces・Permission・deno fmt / lint / test / bench / compile・Standard Library・deno audit・Temporal API・Deno Deploy・Node からの移行・Bun との比較まで、TypeScript の実戦コードで網羅的に解説します。
- 2026 年 4 月時点の Deno バージョン整理
- インストールとプロジェクト作成
- Node.js / npm 互換 ── Deno 2 の核
- パッケージ管理 ── deno install / add / remove
- JSR ── TypeScript ファーストの新レジストリ
- dx コマンド ── npx の代替(Deno 2.6+)
- Workspaces ── deno.json と package.json の混在
- Permission System ── セキュア・バイ・デフォルト
- 組込みツールチェーン ── fmt / lint / test / bench / compile
- Standard Library ── 監査済みユーティリティ
- deno audit / approve-scripts ── サプライチェーンセキュリティ
- Temporal API ── Deno 2.7 で安定化
- Node.js から Deno への移行手順
- Deno vs Bun vs Node.js 比較
- デプロイ ── Deno Deploy / Docker / VPS
- 落とし穴と注意点
- よくある質問
- まとめ
2026 年 4 月時点の Deno バージョン整理
Deno 2 は短期間で多くの重要アップデートが続きました。2026 年 4 月時点の採用なら Deno 2.7 系が標準です。
| リリース | 時期 | 主なハイライト |
|---|---|---|
| Deno 2.0 | 2024 年 10 月 | Node.js / npm 完全互換、npm: / node: 指定子、package.json / node_modules 認識、deno install / add / remove、JSR、安定化された Standard Library、Workspaces |
| Deno 2.1〜2.5 | 2024 年末〜2025 年 | LTS チャンネル開始(2.1)、Temporal 試験実装、パフォーマンス改善、Node 互換性強化 |
| Deno 2.6 | 2025 年 12 月 | dx コマンド(npx 代替)、deno audit / approve-scripts、tsgo(Go 製 TS チェッカ、型チェック 2× 高速)、@types/node 自動バンドル、minimumDependencyAge |
| Deno 2.7 | 2026 年 Q1 | Temporal API 安定化(--unstable-temporal 不要)、Windows ARM 公式ビルド、package.json overrides、Deno.spawn() 新 API、Brotli / SHA3 / File Lock など |
| 推奨 | 2026 年 4 月 | Deno 2.7 系。LTS が必要なら Deno 2.1 LTS 系 |
インストールとプロジェクト作成
# macOS / Linux curl -fsSL https://deno.land/install.sh | sh # Homebrew brew install deno # Windows(PowerShell) irm https://deno.land/install.ps1 | iex # バージョン確認 deno --version # deno 2.7.x (stable, release) # v8 14.x # typescript 5.x # アップグレード deno upgrade
# 対話形式で雛形生成
deno init my-app
# 生成物:
# ├── deno.json ← Deno の設定ファイル
# ├── main.ts
# └── main_test.ts
cd my-app
deno run main.ts
deno test # テストランナー組込み
# Hello world 直接実行(TS ファイルをそのまま)
echo 'console.log("hello deno")' > hello.ts
deno run hello.ts
Node.js / npm 互換 ── Deno 2 の核
Deno 2 最大の変化は 既存 Node.js プロジェクトがほぼそのまま動くことです。package.json と node_modules を自動認識し、npm: / node: 指定子で npm パッケージと Node 組込みモジュールを明示的に取り込めます。
npm: 指定子 ── npm パッケージを直接 import
// npm: 指定子: Deno が自動で npm からダウンロード
import chalk from "npm:chalk@5.3.0";
import express from "npm:express@4.21.2";
import { z } from "npm:zod@3.23.8";
console.log(chalk.blue("hello"));
const app = express();
app.get("/", (_req, res) => res.json({ ok: true }));
app.listen(3000);
// 型もそのまま効く
const Schema = z.object({ name: z.string() });
node: 指定子 ── Node 組込みモジュール
import { readFile } from "node:fs/promises";
import path from "node:path";
import { createHash } from "node:crypto";
const file = await readFile(path.resolve("./data.txt"), "utf-8");
const hash = createHash("sha256").update(file).digest("hex");
console.log(hash);
package.json もそのまま使える
// package.json(Node.js プロジェクトそのまま)
{
"name": "my-app",
"type": "module",
"dependencies": {
"hono": "^4.9.1",
"zod": "^3.23.8"
},
"scripts": {
"dev": "deno run --allow-net src/server.ts"
}
}
# node_modules が未生成なら自動生成される deno install # package.json の scripts を実行 deno task dev # 既存 Express / Next.js / Vite プロジェクトが大半そのまま動く
パッケージ管理 ── deno install / add / remove
# すべての依存をインストール(node_modules 生成) deno install # 省略可: deno i # パッケージ追加 deno add npm:hono # package.json または deno.json に書き込み deno add npm:zod@3.23 deno add jsr:@std/path # JSR から # 削除 deno remove npm:hono # 古い依存の検出 deno outdated # 更新 deno update hono # ロックファイル: deno.lock(JSON) # → Git にコミット必須。CI は --frozen で厳密モード deno install --frozen
deno install は npm 比で冷キャッシュ 15% 高速、ホットキャッシュで 90% 高速。CI 時間がそのまま短縮される恩恵があります。Bun と比べるとわずかに遅いケースもあるものの、セキュリティ機構(Permission・audit)込みのトータルで評価するのが現実的です。JSR ── TypeScript ファーストの新レジストリ
JSR(JavaScript Registry)は Deno チームが運営する TypeScript / ESM ネイティブのパッケージレジストリです。jsr:@scope/name 形式で参照し、Deno / Node.js / Bun から利用できます。
// JSR の Standard Library を使う
import { walk } from "jsr:@std/fs@1";
import { parseArgs } from "jsr:@std/cli@1/parse-args";
const args = parseArgs(Deno.args, { boolean: ["verbose"] });
for await (const entry of walk("./src", { exts: [".ts"] })) {
if (args.verbose) console.log(entry.path);
}
# 公式 CLI: deno publish
# 事前に jsr.io で scope を取得し、deno.json で name と version を設定
cat deno.json
# {
# "name": "@username/my-util",
# "version": "1.0.0",
# "exports": "./mod.ts"
# }
# 公開(GitHub Actions でも npx jsr publish で可)
deno publish
npx jsr add)経由で Node からも使える。npm の歴史的負債(CommonJS 混在・型が別配布・メタデータ欠如)を解消する設計です。dx コマンド ── npx の代替(Deno 2.6+)
# npx 相当。ダウンロード前に確認プロンプトが出る dx cowsay "deno is fast" dx create-react-app my-app dx @astrojs/upgrade latest # JSR パッケージの実行も OK dx jsr:@std/cli@1/parse-args --help # 依存に追加せずに 1 回限り実行 dx prettier . --write
--deny-net などで個別に権限を削ることもできます。明示的に権限を絞りたい場合は deno run --allow-read=./ npm:prettier@3 . --write のような形で使うのが安全です。Workspaces ── deno.json と package.json の混在
{
"workspace": [
"./packages/ui", // deno.json を持つ純 Deno パッケージ
"./packages/api", // package.json を持つ Node 互換パッケージ
"./apps/web" // 同上
],
"imports": {
"@myorg/shared": "./packages/shared/mod.ts"
}
}
# すべてのワークスペースでテスト deno task --recursive test # 特定パッケージのみ deno task --filter=@myorg/api dev
package.json の "workspaces" フィールドがそのまま認識されます。pnpm の pnpm-workspace.yaml も読み取ります。Node から Deno への移行で「モノレポ構造を書き直さなくてよい」のは実務的に大きい利点です。Permission System ── セキュア・バイ・デフォルト
Deno は Node と違い、デフォルトで何もできません。ファイル読み書き・ネットワーク・環境変数アクセスは --allow-* フラグで明示許可が必要です。これが Deno のセキュリティモデルの核です。
# ネットワーク(全許可) deno run --allow-net server.ts # 特定ホストのみ許可(推奨) deno run --allow-net=api.github.com,db.example.com:5432 app.ts # ファイル読み込み(特定ディレクトリのみ) deno run --allow-read=./public,./data app.ts # 環境変数(特定キーのみ) deno run --allow-env=DATABASE_URL,API_KEY app.ts # サブプロセス実行(特定コマンドのみ) deno run --allow-run=git,ls app.ts # すべて許可(開発時のみ。本番禁止) deno run -A app.ts # 実行時に確認プロンプト(--allow-* を付けない場合) deno run server.ts # ⚠️ Deno requests net access to "127.0.0.1:3000". Allow? [y/n (y = yes allow, n = no deny)]
// Permissions API で動的に確認
const status = await Deno.permissions.request({
name: "read",
path: "./secrets",
});
if (status.state !== "granted") {
console.error("権限が足りません");
Deno.exit(1);
}
// 既存の許可状態を問い合わせ
const netStatus = await Deno.permissions.query({ name: "net", host: "api.example.com" });
-A(全許可)を絶対に使わないのが鉄則。実際に必要な許可だけを --allow-net=host1,host2 --allow-read=/app/data --allow-env=DATABASE_URL のように明示する Dockerfile を書いておけば、不正なファイル読み取りや外部通信がランタイムレベルで遮断されます。依存が勝手に外部に接続する事故も防げます。組込みツールチェーン ── fmt / lint / test / bench / compile
# フォーマット(TypeScript / JavaScript / JSON / Markdown / HTML / CSS / YAML 対応)
deno fmt
deno fmt --check # CI で差分があったら fail
# リンター
deno lint
deno lint --rules # 有効ルール一覧
# ルールカスタマイズ(deno.json)
# {
# "fmt": { "lineWidth": 100, "indentWidth": 2, "useTabs": false },
# "lint": { "rules": { "exclude": ["no-explicit-any"] } }
# }
# *_test.ts / *.test.ts を自動実行
deno test
# カバレッジ付き
deno test --coverage
deno coverage --lcov > coverage.lcov
# 並列実行
deno test --parallel
# Node.js の node:test ライクなテストも動く
# import { test } from "node:test";
import { assertEquals } from "jsr:@std/assert@1";
Deno.test("add function", () => {
assertEquals(2 + 3, 5);
});
Deno.test("async test", async () => {
const res = await fetch("https://httpbin.org/get");
assertEquals(res.status, 200);
await res.body?.cancel();
});
// スナップショット
import { assertSnapshot } from "jsr:@std/testing@1/snapshot";
Deno.test("snapshot", async (t) => {
await assertSnapshot(t, { user: "alice", age: 25 });
});
# ベンチマーク deno bench # Single-file executable(Node.js 不要のバイナリ化) deno compile --output mycli --allow-net src/cli.ts # クロスコンパイル deno compile --target x86_64-unknown-linux-gnu --output mycli-linux src/cli.ts deno compile --target x86_64-pc-windows-msvc --output mycli.exe src/cli.ts deno compile --target aarch64-apple-darwin --output mycli-mac src/cli.ts deno compile --target aarch64-pc-windows-msvc --output mycli-winarm src/cli.ts # 2.7+
Standard Library ── 監査済みユーティリティ
Deno Standard Library(@std/*)は Deno 2 で安定化し、データ操作・Web・ファイル・暗号・CLI・テストなどのモジュールを依存追加なしで使えます。TypeScript ネイティブ・セキュリティ監査済み・セマンティックバージョニングが保証されます。
// ファイルシステム
import { walk, copy, ensureDir } from "jsr:@std/fs@1";
// パス操作
import { join, resolve, extname } from "jsr:@std/path@1";
// 非同期ユーティリティ
import { debounce, pooledMap } from "jsr:@std/async@1";
// CLI 引数パース
import { parseArgs } from "jsr:@std/cli@1/parse-args";
// 暗号ハッシュ
import { crypto } from "jsr:@std/crypto@1";
// JSON schema + 型ガード
import { assert, assertEquals } from "jsr:@std/assert@1";
// URL パターンマッチ
import { UrlPattern } from "jsr:@std/http@1/unstable-url-pattern";
deno audit / approve-scripts ── サプライチェーンセキュリティ
# すべての依存を GitHub Advisory Database で検査 deno audit # 重大度で絞り込み deno audit --severity=high # JSON 出力(CI 向け) deno audit --json
# 依存の postinstall / preinstall などを承認制に deno approve-scripts # インタラクティブに実行を許可 # ✓ sharp: rebuild native binary (必要) # ✗ telemetry-package: unwanted script (拒否)
deno.json に "minimumDependencyAge": "7d" を書くと、リリース後 7 日未満のバージョンが拒否されます。最近の npm 界のサプライチェーン攻撃(公開直後の悪意ある更新)を静的に回避できるので、企業プロジェクトでは設定推奨です。Temporal API ── Deno 2.7 で安定化
// 2.7 以降はフラグなしで使える
const now = Temporal.Now.plainDateTimeISO();
console.log(now.toString()); // 2026-04-22T09:30:45.123
// 不変・タイムゾーン対応
const start = Temporal.PlainDate.from("2026-04-01");
const end = Temporal.PlainDate.from("2026-04-22");
const days = start.until(end).days; // 21
// 厳密な計算
const meeting = Temporal.ZonedDateTime.from({
timeZone: "Asia/Tokyo",
year: 2026, month: 4, day: 22, hour: 14, minute: 30,
});
const utc = meeting.withTimeZone("UTC");
Date は 1995 年から続くレガシー API で、タイムゾーン扱い・ミュータブルな API・月が 0 始まりなど多くの地雷がありました。Temporal は TC39 標準として再設計され、不変オブジェクト・タイムゾーン明示・カレンダー対応を実現。Deno 2.7 が標準ランタイムで最初に安定投入した形です。Node.js から Deno への移行手順
| ステップ | やること | ポイント |
|---|---|---|
| ① ランタイム切り替え | node server.js → deno run --allow-net server.js |
権限フラグで必要な許可だけ与える。落ちる箇所を Permission 起因かコード起因かで切り分け |
| ② スクリプト層 | package.json scripts → deno task |
既存 scripts はそのまま動く。deno task dev で実行 |
| ③ テスト | Jest / Vitest → deno test または Node 互換のまま併用 |
小さいパッケージから移行。Jest スナップショットは手作業変換 |
| ④ 依存見直し | npm:xxx を jsr:@std/xxx に置換 |
lodash → Std、dayjs → Temporal など段階的に |
| ⑤ 本番 Runtime | Docker ベースイメージを denoland/deno に |
–allow-* を本番用に明示。-A は禁止 |
sharp、bcrypt、canvas のような C++ 依存を含むパッケージは必ず CI で動作確認してから本番投入してください。deno check で型エラーを事前に洗い出すのも有効です。Deno vs Bun vs Node.js 比較
| 観点 | Deno 2.7 | Bun 1.3 | Node.js 22 |
|---|---|---|---|
| TypeScript 直接実行 | ○ ゼロ設定 | ○ ゼロ設定 | △ --experimental-strip-types または tsx / ts-node |
| Node 互換 | ○(npm: / node: 指定子) | ○ 高い互換性 | —(本家) |
| Permission System | ◎ 標準セキュア | △ 実験的 | △ --permission(実験的) |
| 独自レジストリ | JSR(TS ネイティブ) | npm のみ | npm のみ |
| 組込みツール | fmt / lint / test / bench / compile / audit | build / test / run | node:test(最小) |
| パッケージ速度 | ○ | ◎ 最速 | △ |
| エッジ対応 | Deno Deploy(エッジ専用) | Cloudflare Workers 非対応 | 一部対応 |
| 型チェック速度 | tsgo(Go 製、2× 高速) | tsc(外部) | tsc(外部) |
| 成熟度 | ○ 安定 | ○ 本番実績増 | ◎ 最長の実績 |
デプロイ ── Deno Deploy / Docker / VPS
Deno Deploy(公式エッジプラットフォーム)
# deployctl CLI deno install -Arf jsr:@deno/deployctl # デプロイ deployctl deploy --project=my-app src/server.ts # 本番環境変数 deployctl env set DATABASE_URL=... --project=my-app
Deno.openKv())が組込み、③ GitHub 統合で PR プレビュー自動生成、④ 請求単位が実行時間ではなく「リクエスト+CPU 時間」なので低トラフィック時のコストが安い。Cloudflare Workers と比較検討される選択肢です。Docker でセルフホスト
FROM denoland/deno:2.7.0 AS deps WORKDIR /app COPY deno.json deno.lock ./ RUN deno install --frozen FROM denoland/deno:2.7.0 WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . # 権限は明示的に絞る(本番では -A を使わない) USER deno EXPOSE 8000 CMD ["run", "--allow-net", "--allow-env=DATABASE_URL", "src/server.ts"]
Single-file executable
# 実行可能バイナリを作成(Deno ランタイムを内包) deno compile \ --allow-net --allow-env \ --target x86_64-unknown-linux-gnu \ --output server-linux \ src/server.ts # 60MB 程度の単一ファイル。scp して実行するだけ scp server-linux user@host:/opt/app/ ssh user@host "/opt/app/server-linux"
落とし穴と注意点
Permission フラグの付け忘れで突然落ちる
開発では -A で動いていた処理が、本番で「Permission denied」になる。原因のほとんどはライブラリが内部的に fetch や readFile を呼んでいるケース。本番デプロイ前にステージングで 実際の本番フラグで 1 時間は流すのが事故を防ぐ最短ルートです。
npm: 指定子と node_modules のハイブリッド混在
同じプロジェクトで npm: 指定子と node_modules(package.json 経由)を混ぜると、バージョン解決が競合することがあります。原則どちらか一方に寄せ、Node 互換移行中は package.json に統一、Deno ネイティブに寄せたら deno.json の imports に集約するのが整理しやすいです。
CommonJS モジュールに手を焼く
Deno 2 は CJS 互換が大きく改善しましたが、一部の古いパッケージ(動的 require() やモンキーパッチをするもの)は動きません。deno doctor(将来追加予定)や deno check で依存解析し、問題のあるパッケージは npm: の代替品や JSR ネイティブ代替を探してください。
deno.lock を消さない
ロックファイルはバージョン再現性の要。開発者が手癖で rm -rf node_modules *.lock と書くチームは事故を起こしがちです。CI では deno install --frozen を使い、ロックファイルが変わっていたらビルド失敗する運用にしておきます。
Temporal は 2.7 以降
2.6 以前で Temporal を使う場合は --unstable-temporal フラグが必要です。2.7 以降は不要ですが、チームメンバーの Deno バージョンが揃っていないと実行時に落ちるので、deno.json で最低バージョンを指定しておくとトラブルを防げます。
dx のデフォルト全権限
dx は利便性のためデフォルト全権限で動きます。信頼できないパッケージを実行する前に dx --help でパッケージ情報を確認するか、dx --deny-net some-pkg のように権限を削る習慣をつけてください。企業環境では deno run --allow-read=./ npm:prettier@3 . --write のように deno run で明示する方が安全です。
よくある質問
Deno.openKv()・Deno.serve()・Deno.cron())をフル活用したいなら Deno Deploy。既存の Node コードベース・Durable Objects・豊富なバインディングを使うなら Cloudflare Workers。Hono / Bun / Astro は両方動くので、自社の認証基盤・KV・ワーカー要件で判断するのが現実的です。"type": "module" を書いておくのが推奨です。書いていなくても Deno は動きますが、Node でも同じコードを動かす前提ならモジュール種別を明示した方がハマりません。TypeScript の tsconfig.json も "module": "ESNext" にしておきます。--compat フラグや node: 指定子経由で CJS モジュールを読む場合は使えます。ESM では import.meta.url や new URL(".", import.meta.url) を使うのが Web 標準。Deno ネイティブなら import.meta.dirname / import.meta.filename(Node 20+ でもサポート)で同等のことが書けます。まとめ
- Deno 2.7 が 2026 年の本命: Node/npm 互換・JSR・dx・Workspaces・Temporal 安定化が揃い、Node から Deno への移行コストが最小化された
- Node/npm 互換:
npm:/node:指定子とpackage.json認識で、既存プロジェクトがほぼそのまま動く - パッケージ管理:
deno install / add / remove / outdated / updateが npm 比で冷キャッシュ 15% 高速、ホット 90% 高速 - JSR: TypeScript ネイティブ・ESM 強制・自動ドキュメントの新レジストリ。Deno / Node / Bun すべてで使える
- dx コマンド(2.6+)で npx 相当の使い捨て実行。
deno audit/approve-scripts/minimumDependencyAgeでサプライチェーン対策 - Permission System: セキュア・バイ・デフォルト。本番は
-A禁止、必要な--allow-*のみ付与 - 組込みツール: fmt / lint / test / bench / compile / audit が 1 バイナリで動く。tsgo で型チェック 2× 高速
- Temporal API 安定化(2.7): Date のレガシーから解放。不変・タイムゾーン対応の新・日時 API
- デプロイは Deno Deploy / Docker / Single-file executable の 3 択。エッジ優先なら Deno Deploy、柔軟性なら Docker
JS ランタイム選択のもう一方の選択肢として Bun 完全ガイド、Web 標準 API ベースで Deno と相性が良い TypeScript × Hono 完全ガイド、データ層は TypeScript × Drizzle ORM 完全ガイド、フロントエンド連携は React 19 完全ガイド・Astro 完全ガイド・Svelte 5 完全ガイド、バックエンド連携は Claude Code × Supabase フルスタック開発完全ガイド もあわせてご覧ください。
