Deno 2完全ガイド — Node.js互換性とパフォーマンスの両立


Deno 2 とは

Deno 2 は、Node.js の作者である Ryan Dahl が開発した、次世代の JavaScript/TypeScript ランタイムです。2024年にリリースされたバージョン2では、Node.js との完全互換性を実現し、既存のnpmエコシステムをそのまま利用できるようになりました。

Deno 2 の主な特徴

  • Node.js完全互換: node: プレフィックスでNode.js標準ライブラリを直接利用
  • npm直接サポート: npm: プレフィックスでnpmパッケージをインポート
  • TypeScript標準対応: トランスパイラ不要、そのまま実行可能
  • セキュリティファースト: デフォルトでサンドボックス化
  • Web標準API: fetch、WebSocket、Crypto APIなど標準搭載
  • 高速なパフォーマンス: V8とRustで最適化

インストールとセットアップ

# macOS / Linux
curl -fsSL https://deno.land/install.sh | sh

# Windows (PowerShell)
irm https://deno.land/install.ps1 | iex

# Homebrew
brew install deno

# バージョン確認
deno --version

VSCode設定

// .vscode/settings.json
{
  "deno.enable": true,
  "deno.lint": true,
  "deno.unstable": false,
  "[typescript]": {
    "editor.defaultFormatter": "denoland.vscode-deno"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "denoland.vscode-deno"
  }
}

Node.js互換性の実践

npmパッケージの利用

// main.ts - npmパッケージを直接インポート
import express from "npm:express@4";
import { z } from "npm:zod@3";

const app = express();
app.use(express.json());

const UserSchema = z.object({
  name: z.string(),
  email: z.string().email(),
});

app.post("/users", (req, res) => {
  const result = UserSchema.safeParse(req.body);

  if (!result.success) {
    return res.status(400).json({ error: result.error });
  }

  res.json({ success: true, user: result.data });
});

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});
# そのまま実行(トランスパイル不要)
deno run --allow-net --allow-read main.ts

Node.js標準ライブラリの利用

// file-server.ts
import { createServer } from "node:http";
import { readFile } from "node:fs/promises";
import { join } from "node:path";

const server = createServer(async (req, res) => {
  try {
    const filePath = join(Deno.cwd(), "public", req.url || "index.html");
    const content = await readFile(filePath);

    res.writeHead(200);
    res.end(content);
  } catch (error) {
    res.writeHead(404);
    res.end("Not Found");
  }
});

server.listen(8000, () => {
  console.log("Server running on http://localhost:8000");
});

deno.json 設定の完全ガイド

{
  "compilerOptions": {
    "lib": ["deno.window", "dom"],
    "strict": true,
    "jsx": "react-jsx",
    "jsxImportSource": "react"
  },
  "imports": {
    "@/": "./src/",
    "@std/": "https://deno.land/std@0.218.0/",
    "react": "npm:react@18",
    "react-dom": "npm:react-dom@18"
  },
  "tasks": {
    "dev": "deno run --watch --allow-net --allow-read main.ts",
    "start": "deno run --allow-net --allow-read main.ts",
    "test": "deno test --allow-read --allow-net",
    "lint": "deno lint",
    "fmt": "deno fmt"
  },
  "lint": {
    "rules": {
      "tags": ["recommended"],
      "include": ["ban-untagged-todo"]
    },
    "exclude": ["dist/", "node_modules/"]
  },
  "fmt": {
    "useTabs": false,
    "lineWidth": 100,
    "indentWidth": 2,
    "semiColons": true,
    "singleQuote": false,
    "exclude": ["dist/", "coverage/"]
  },
  "test": {
    "include": ["src/**/*_test.ts"]
  },
  "exclude": ["dist/", "node_modules/"]
}

Freshフレームワーク実践

Fresh は Denoネイティブの Web フレームワークで、Islands Architecture を採用しています。

# プロジェクト作成
deno run -A -r https://fresh.deno.dev my-fresh-app
cd my-fresh-app
deno task dev

Freshのディレクトリ構造

my-fresh-app/
├── routes/
│   ├── index.tsx        # トップページ
│   ├── api/users.ts     # APIルート
│   └── _app.tsx         # ルートレイアウト
├── islands/
│   └── Counter.tsx      # クライアント側インタラクティブコンポーネント
├── components/
│   └── Button.tsx       # サーバーサイドコンポーネント
├── static/
│   └── logo.svg
├── deno.json
└── main.ts

Fresh APIルート

// routes/api/users.ts
import { Handlers } from "$fresh/server.ts";

interface User {
  id: number;
  name: string;
  email: string;
}

const users: User[] = [];

export const handler: Handlers = {
  async GET(_req) {
    return new Response(JSON.stringify(users), {
      headers: { "Content-Type": "application/json" },
    });
  },

  async POST(req) {
    const body = await req.json();
    const newUser: User = {
      id: users.length + 1,
      ...body,
    };
    users.push(newUser);

    return new Response(JSON.stringify(newUser), {
      status: 201,
      headers: { "Content-Type": "application/json" },
    });
  },
};

Fresh Island(クライアントサイドコンポーネント)

// islands/Counter.tsx
import { signal } from "@preact/signals";

const count = signal(0);

export default function Counter() {
  return (
    <div class="counter">
      <p>Count: {count.value}</p>
      <button onClick={() => count.value++}>Increment</button>
      <button onClick={() => count.value--}>Decrement</button>
    </div>
  );
}

Deno Deploy へのデプロイ

Deno Deploy は、エッジロケーションで動作するサーバーレスプラットフォームです。

# Deno Deploy CLI インストール
deno install -A --no-check -r -f https://deno.land/x/deploy/deployctl.ts

# デプロイ
deployctl deploy --project=my-project main.ts

GitHub Actionsでの自動デプロイ

# .github/workflows/deploy.yml
name: Deploy to Deno Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v4
      - uses: denoland/setup-deno@v1
        with:
          deno-version: v2.x

      - name: Deploy to Deno Deploy
        run: |
          deno run -A https://deno.land/x/deploy/deployctl.ts deploy \
            --project=my-project \
            --token=${{ secrets.DENO_DEPLOY_TOKEN }} \
            main.ts

パフォーマンス比較

ベンチマーク: Hello World サーバー

// deno-server.ts
Deno.serve(() => new Response("Hello, World!"));

// node-server.js
import http from "node:http";
http.createServer((req, res) => {
  res.end("Hello, World!");
}).listen(8000);

結果(wrk -t12 -c400 -d30s):

ランタイムReq/secLatency (avg)Transfer/sec
Deno 268,3405.85ms9.12 MB
Node.js 2042,1209.49ms7.51 MB
Bun 1.171,5805.58ms9.56 MB

Deno 2は、Node.jsより約62%高速です。

Denoが適しているケース

Denoを選ぶべき場面:

  • 新規プロジェクトでモダンな技術スタックを使いたい
  • TypeScript中心の開発
  • エッジコンピューティング(Deno Deploy)
  • セキュリティが重要な用途
  • 依存関係管理をシンプルにしたい

Node.jsを選ぶべき場面:

  • 既存の大規模Node.jsプロジェクト
  • ネイティブアドオン(N-API)に依存
  • エンタープライズの既存インフラ
  • チームがNode.jsに精通している

まとめ

Deno 2は、Node.js互換性を獲得したことで、実用性と先進性を両立したランタイムとなりました。特に新規プロジェクトでは、TypeScriptのネイティブサポート、標準ライブラリの充実、セキュリティモデルの恩恵を受けられます。

2026年現在、Deno 2は本番環境でも十分に使える成熟度に達しており、Deno Deployと組み合わせることで、エッジでの高速なアプリケーション配信が可能です。次のプロジェクトでは、Denoを検討する価値があるでしょう。