1. 採用技術一覧

Frontend / Framework
Next.js (App Router) 15.x RSC + Route Handlers で統一的な開発体験
TypeScript 5.x 型安全性・開発体験の向上
Prisma 6.x 型安全な DB アクセス・マイグレーション管理
@prisma/adapter-d1 6.x Prisma から Cloudflare D1 へ接続するアダプタ
Cloudflare Platform
Cloudflare Workers OpenNext の Workers アセット出力でホスティング
@opennextjs/cloudflare 1.x Next.js を Cloudflare Workers にデプロイするアダプタ
Cloudflare D1 SQLite 互換のサーバーレスエッジ DB
Cloudflare R2 S3 互換のオブジェクトストレージ(画像保存)
Cloudflare Queues 画像最適化の非同期処理
wrangler 4.x D1 / R2 / Queues ローカルエミュレーション
Data & State Management
TanStack Query 5.x 宣言的なデータフェッチ・自動キャッシュ
TanStack Table 8.x Headless UI・高機能テーブル
Jotai 2.x 軽量・atom ベースのグローバル状態
React Hook Form 7.x 高パフォーマンスなフォーム管理
Zod 3.x スキーマ定義・フロント / バック共有
@jsquash/* latest WebP 変換(Workers 上で動作する wasm ベース)
🎨 UI / Styling
shadcn/ui latest Radix UI ベース・Tailwind CSS 統合
Tailwind CSS 3.x ユーティリティファースト CSS
framer-motion 12.x UI アニメーション
lucide-react latest SVG アイコンセット
sonner 2.x トースト通知
cmdk 1.x コマンドパレット UI
next-themes latest ライト / ダークモード管理
tailwind-merge 2.x Tailwind クラス名マージ
🧪 Testing & Tooling
Biome 1.x Rust 製高速ツール・ESLint + Prettier 代替
Vitest 4.x Vite ベース・Jest 互換の高速テスト
@cloudflare/vitest-pool-workers latest workerd / Miniflare 上での D1 統合テスト
Playwright 1.x クロスブラウザ E2E テスト
pnpm 10.x 高速・効率的なパッケージ管理

2. 技術選定の詳細

Next.js App Router + @opennextjs/cloudflare

Route Handler の基本構造
import { getCloudflareContext } from "@opennextjs/cloudflare"

export async function GET(request: Request) {
  const { env } = await getCloudflareContext({ async: true })
  const prisma = createPrismaClient(env.DB)  // D1 バインディングを渡す
  // ...
}

Prisma + Cloudflare D1

prisma/schema.prisma
datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")  // ローカル開発時のみ参照
}
src/lib/prisma.ts
import { PrismaClient } from "@prisma/client"
import { PrismaD1 } from "@prisma/adapter-d1"

export function createPrismaClient(d1: D1Database): PrismaClient {
  const adapter = new PrismaD1(d1)
  return new PrismaClient({ adapter })
}

Cloudflare D1 の特徴

項目内容
互換性SQLite 互換 SQL
ロケーションCloudflare エッジネットワーク(自動分散)
料金無料枠: 500万行/日の読み取り、10万行/日の書き込み
マイグレーションwrangler d1 migrations apply <DB_NAME>
ローカル開発wrangler dev.wrangler/state/ に SQLite ファイルを自動作成
バックアップCloudflare ダッシュボードからエクスポート可能

Cloudflare R2(画像ストレージ)

Cloudflare Queues + 画像最適化 Worker

wrangler.toml 設定概要

name = "aws-glossary"
main = ".open-next/worker.js"
compatibility_date = "2024-09-23"
compatibility_flags = ["nodejs_compat", "global_fetch_strictly_public"]

[assets]
directory = ".open-next/assets"
binding = "ASSETS"

[[services]]
binding = "WORKER_SELF_REFERENCE"
service = "aws-glossary"

[[d1_databases]]
binding = "DB"
database_name = "aws-glossary-db"
database_id = "<D1_DATABASE_ID>"
migrations_dir = "prisma/migrations"

[[r2_buckets]]
binding = "TERM_IMAGES"
bucket_name = "aws-glossary-images"
# remote = true は設定しない(ローカルは Miniflare in-memory R2 を使用)

[[queues.producers]]
binding = "IMAGE_OPTIMIZE_QUEUE"
queue = "aws-glossary-image-optimize"

TanStack Query

// QueryClient 設定
{
  staleTime: 30 * 1000,       // 30秒
  gcTime: 5 * 60 * 1000,      // 5分
  retry: 1,
  refetchOnWindowFocus: false,
}

// Query Key 形式
["terms", "list", { q, searchBy, category, page }]

Biome

// biome.json(主要設定)
{
  "linter": { "enabled": true },
  "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2 },
  "javascript": { "formatter": { "quoteStyle": "double" } }
}

Vitest(t-wada TDD スタイル)

Playwright

3. Cloudflare への公開(最終形態)

本プロジェクトの本番公開は Cloudflare Workers(OpenNext の Workers アセット出力)を前提とする。

要素採用内容
ホスティングCloudflare Workers([assets] バインディングで静的アセット配信)
Next.js ビルド@opennextjs/cloudflare(OpenNext の Cloudflare アダプター)
DBCloudflare D1 + @prisma/adapter-d1
画像ストレージCloudflare R2(env.TERM_IMAGES
非同期処理Cloudflare Queues + 画像最適化 Worker(別 Worker)
Route HandlersgetCloudflareContext({ async: true }) で各バインディングに接続

デプロイの一般的な流れ

  1. OpenNext ビルドopennextjs-cloudflare build を実行(.open-next/worker.js + .open-next/assets/ を出力)
  2. Workers へのデプロイopennextjs-cloudflare deploy(内部で wrangler deploy)— pnpm deploy に集約
  3. 画像最適化 Worker のデプロイpnpm deploy:image-workerwrangler deploy -c wrangler.image-optimizer.toml

押さえておく制約(Workers ランタイム)

Node.js フル互換ではない: next start 前提のパッケージは動かないことがある。compatibility_flags = ["nodejs_compat", "global_fetch_strictly_public"] を指定すること。

公式参照リンク

4. 依存関係

dependencies
next
react / react-dom
@prisma/client
@prisma/adapter-d1          # D1 アダプタ
@opennextjs/cloudflare      # Cloudflare Workers デプロイアダプタ
@tanstack/react-query
@tanstack/react-table
jotai
react-hook-form
zod
@hookform/resolvers         # RHF + Zod インテグレーション
sonner                      # トースト通知
framer-motion               # アニメーション
cmdk                        # コマンドパレット
next-themes                 # ダークモード
lucide-react                # アイコン
tailwind-merge
class-variance-authority
@jsquash/jpeg / png / webp / resize  # Workers 上の画像処理
devDependencies
prisma
wrangler                         # D1 ローカル開発・マイグレーション
typescript / @types/react / @types/node
@cloudflare/workers-types        # D1Database・R2Bucket・Queue 等の型定義
tailwindcss
@biomejs/biome
vitest                           # 4.x
@cloudflare/vitest-pool-workers
@testing-library/react
@testing-library/user-event
@playwright/test
shadcn                           # shadcn/ui CLI