設計

Next.jsプロジェクトにTurso + Drizzle ORMをローカル環境で導入する完全ガイド

SQLiteファイル直接使用パターンでTursoとDrizzle ORMをセットアップし、本番環境と同じ環境変数で開発する方法を解説

この記事では、Next.js プロジェクトに Turso と Drizzle ORM を導入し、ローカル環境で開発するための設定をステップバイステップで解説します。

前提条件

  • Next.js プロジェクトが作成済み
  • Node.js がインストール済み

ステップ1: パッケージのインストール

# npm
npm install drizzle-orm @libsql/client
npm install -D drizzle-kit

# pnpm
pnpm add drizzle-orm @libsql/client
pnpm add -D drizzle-kit

ステップ2: 環境変数の設定

本番環境と同じ環境変数名を使用することで、環境ごとの切り替えを容易にします。

.env

NEXT_PUBLIC_SITE_URL="https://example.com"

# Turso Database (ローカル: file:local.db / 本番: libsql://xxx.turso.io)
TURSO_DATABASE_URL="file:local.db"
# ローカルではダミー値を設定しておく
TURSO_AUTH_TOKEN="dummy_token_for_local"

.env.example

NEXT_PUBLIC_SITE_URL="https://example.com"

# Turso Database (ローカル: file:local.db / 本番: libsql://xxx.turso.io)
TURSO_DATABASE_URL="file:local.db"
# ローカルではダミー値を設定しておく
TURSO_AUTH_TOKEN="dummy_token_for_local"

重要: file: プレフィックスは libSQL クライアントの要件です。

ステップ3: T3 Env で環境変数を型安全に管理

src/env.ts:

import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const env = createEnv({
  server: {
    // ローカル: file:local.db
    // 本番: libsql://xxx.turso.io
    TURSO_DATABASE_URL: z
      .string()
      .refine((url) => url.startsWith("file:") || url.startsWith("libsql://"), {
        message: "TURSO_DATABASE_URL must start with 'file:' or 'libsql://'",
      }),
    // ローカルではダミー値を設定しておく
    TURSO_AUTH_TOKEN: z.string(),
  },
  client: {
    NEXT_PUBLIC_SITE_URL: z.string().url(),
  },
  experimental__runtimeEnv: {
    NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
  },
});

ステップ4: データベーススキーマの定義

src/db/schema.ts:

import { sql } from "drizzle-orm";
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const users = sqliteTable("users", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  name: text("name").notNull(),
  email: text("email").notNull().unique(),
  createdAt: text("created_at").notNull().default(sql`(datetime('now'))`),
});

export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;

ステップ5: データベース接続の設定

src/db/index.ts:

import { createClient } from "@libsql/client";
import { drizzle } from "drizzle-orm/libsql";
import { env } from "@/env";
import * as schema from "./schema";

const client = createClient({
  url: env.TURSO_DATABASE_URL,
  authToken: env.TURSO_AUTH_TOKEN || undefined,
});

export const db = drizzle(client, { schema });

ステップ6: Drizzle Kit の設定

drizzle.config.ts:

import { defineConfig } from "drizzle-kit";
import { env } from "./src/env";

export default defineConfig({
  schema: "./src/db/schema.ts",
  out: "./drizzle",
  dialect: "turso",
  dbCredentials: {
    url: env.TURSO_DATABASE_URL,
    authToken: env.TURSO_AUTH_TOKEN,
  },
});

ステップ7: package.json にスクリプトを追加

{
  "scripts": {
    "db:generate": "drizzle-kit generate",
    "db:migrate": "drizzle-kit migrate",
    "db:studio": "drizzle-kit studio"
  }
}

注意: db:push は使用しません。必ずマイグレーションファイルを作成してからマイグレーションを実行します。

ステップ8: .gitignore にローカルDBファイルを追加

# Local SQLite database
local.db
local.db-shm
local.db-wal

ステップ9: マイグレーションの実行

# マイグレーションファイルを生成
npm run db:generate

# マイグレーションを実行
npm run db:migrate

データベースのリセット方法

ローカルデータベースをリセットしたい場合:

# 1. 開発サーバーを停止(起動中の場合)

# 2. 全ての関連ファイルを削除
rm -f local.db local.db-shm local.db-wal

# 3. マイグレーションを実行
npm run db:migrate

[✓] migrations applied successfully! と表示されれば成功です。

Drizzle Studio でデータを確認

npm run db:studio

ブラウザで https://local.drizzle.studio にアクセスすると、GUI でデータベースの内容を確認・編集できます。

SQLite WAL モードと 3 つのファイル

SQLite は WAL(Write-Ahead Logging)モードを使用する際、3 つのファイルを生成します。

ファイル役割
local.dbメインデータベースファイル
local.db-wal書き込み先行ログ(WAL)
local.db-shm共有メモリ / WAL インデックス

各ファイルの詳細

local.db - メインデータベースファイル

実際のデータベース内容を格納するファイルです。テーブル、インデックス、データがすべてここに保存されます。

local.db-wal - Write-Ahead Log

  • コミットされたが、まだメインデータベースに適用されていないトランザクションを記録
  • 約 1000 ページ(約 4MB)蓄積されると自動的にチェックポイントが実行され、内容がメインデータベースに統合される

local.db-shm - Shared Memory

  • データベースファイルではなく、共有メモリとして使用される
  • 複数のプロセス/接続が WAL ファイル内のフレームを素早く検索するためのインデックスをキャッシュ
  • データベースの内容は含まない(一時的なデータのみ)

ファイルのライフサイクル

[データベース使用中]
  local.db + local.db-wal + local.db-shm  ← 3 ファイルが存在

[正常終了時]
  自動チェックポイント実行
  → WAL の内容がメイン DB に統合
  → local.db-wal と local.db-shm は削除される

[結果]
  local.db のみが残る

データベースを使用しているプロセスがない場合、local.db のみが存在するのは正常な状態です。

本番環境への切り替え

本番環境では、環境変数を以下のように設定するだけで切り替えられます:

TURSO_DATABASE_URL="libsql://your-database.turso.io"
TURSO_AUTH_TOKEN="your-actual-token"

コードの変更は不要です。

使用例

import { db } from "@/db";
import { users } from "@/db/schema";
import { eq } from "drizzle-orm";

// 全ユーザー取得
const allUsers = await db.select().from(users);

// ユーザー作成
await db.insert(users).values({
  name: "John",
  email: "john@example.com",
});

// ユーザー更新
await db
  .update(users)
  .set({ name: "John Doe" })
  .where(eq(users.id, 1));

// ユーザー削除
await db.delete(users).where(eq(users.id, 1));

まとめ

項目設定
データベース方式SQLite ファイル直接使用
環境変数TURSO_DATABASE_URL, TURSO_AUTH_TOKEN
マイグレーションdb:generatedb:migrate
GUI 確認db:studio

この構成により、ローカル開発と本番環境で同じコードを使用し、環境変数の値だけで切り替えが可能になります。