この記事では、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:generate → db:migrate |
| GUI 確認 | db:studio |
この構成により、ローカル開発と本番環境で同じコードを使用し、環境変数の値だけで切り替えが可能になります。