1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DBマイグレーション運用術:開発・本番環境を安全に管理する方法

Last updated at Posted at 2025-12-08

この記事は、ひとりでつくるSaaS - 設計・実装・運用の記録 Advent Calendar 2025 の8日目の記事です。

昨日の記事では「データベースのID設計」について書きました。この記事では、DBマイグレーションの運用方法について解説します。

この記事で紹介する方法は、試行錯誤の末にたどり着いた独自のやり方です。もっと良い方法があれば、ぜひコメントで教えてください。

🎯 一般的なマイグレーション管理の方法

DBマイグレーションには、いくつかの管理方法があります。

ORMのマイグレーション機能を使う

Drizzle ORM、Prisma、TypeORMなどのORMには、マイグレーション機能が組み込まれています。

# Drizzle ORMの場合
npx drizzle-kit generate  # スキーマからマイグレーションを生成
npx drizzle-kit migrate   # マイグレーションを適用

たとえば、TypeScriptでテーブル定義を書くと、その変更を検出して ALTER TABLE などのSQLを自動生成してくれます。

メリット:

  • コードの変更から自動でマイグレーションSQLを生成
  • 適用履歴をDBのテーブルで管理
  • コマンド一発で適用できる

課題:

  • 複雑なデータ移行(既存データの変換など)には対応しにくい
  • 何が実行されるか把握しづらいことがある

複数環境を管理する場合の課題

ORMのマイグレーション機能は単一環境の管理には便利ですが、開発環境と本番環境を分けて運用する場合、以下のような課題があります。

  • 開発環境と本番環境でスキーマが合わなくなる
  • 「開発で適用したが本番にはまだ」という状態が把握しづらい
  • 何をいつ適用したか分からなくなる

私が開発しているMemoreruでも同じ課題に直面し、試行錯誤の結果、現在のような運用ルールにたどり着きました。

📂 個人開発プロダクトでのマイグレーション管理

連番ファイルで時系列管理

マイグレーションファイルはClaude Codeに作成してもらい、連番で管理しています。

database/migrations/
├── sql/
│   ├── 001_create_users_table.sql
│   ├── 002_create_posts_table.sql
│   ├── 003_add_user_profile.sql
│   ├── 004_add_status_column.sql
│   └── ...
├── scripts/
│   └── migrate.sh
├── status.json
└── README.md

連番管理のメリット:

  • 適用順序が一目で分かる
  • ファイル名でどの時点のスキーマか分かる
  • 本番と開発の差分を把握しやすい

SQLファイルを直接管理する理由

Drizzle ORMのマイグレーション生成機能(drizzle-kit generate)は使わず、SQLファイルを直接作成しています。ただし、スキーマ定義自体はDrizzle ORMで管理しているため、型安全性は保たれています。

SQLファイルを直接管理する理由:

  • 複雑な変更(データ移行を伴うもの)に対応しやすい
  • 何が実行されるか完全に把握できる
  • トラブル時の原因特定が容易

🔄 開発・本番共通のマイグレーションスクリプト

Memoreruでは、開発環境と本番環境で同じスクリプトを使ってマイグレーションを適用しています。

なぜ共通スクリプトか

# 開発環境
./database/migrations/scripts/migrate.sh dev 004_add_status_column.sql

# 本番環境
./database/migrations/scripts/migrate.sh pro 004_add_status_column.sql

共通スクリプトのメリット:

  1. リハーサル効果: 開発環境で本番と同じ手順を踏むことで、本番適用前に問題を発見できる
  2. 手順の統一: 開発はClaude Codeで直接実行、本番はスクリプト...という違いがあると事故のもと
  3. ログの一元管理: 両環境の実行ログが同じ形式で残る

環境別の違い

項目 開発環境 本番環境
接続情報 .env.localから自動読み込み 毎回手動入力
バックアップ推奨 なし 警告表示

本番環境の接続文字列を毎回入力するのは手間ですが、これが安全策として機能します。誤って開発環境のつもりで本番を操作する事故を防げます。

また、Claude Codeには本番環境のDB接続情報を教えていません。これにより、AIが誤って本番DBを操作するリスクを排除しています。

なお、どちらの環境でもマイグレーション適用前にpgAdminのバックアップ機能でバックアップを取得しています。万が一のロールバックに備えておくことが大切です。

🛡️ 安全に適用するための仕組み

スクリプトには以下のような安全策を組み込んでいます。

  • 確認フロー: 適用前に確認プロンプトを表示し、誤操作を防ぐ
  • 接続テスト: 適用前にDBへの接続を確認
  • ログの自動保存: すべての実行ログを logs/migrations/ に保存し、後から確認できるようにする

スクリプトの具体的な実装はClaude Codeに作成してもらいました。要件を伝えれば、環境に合わせたスクリプトを生成してくれます。

📊 status.jsonで適用状況を一元管理

開発環境と本番環境の適用状況を1つのファイルで管理しています。

{
  "lastUpdated": "2025-12-04",
  "environments": {
    "dev": {
      "name": "開発環境",
      "lastApplied": "004_add_status_column",
      "appliedAt": "2025-12-04"
    },
    "pro": {
      "name": "本番環境",
      "lastApplied": "003_add_user_profile",
      "appliedAt": "2025-11-30"
    }
  },
  "pending": {
    "pro": ["004_add_status_column"]
  }
}

本番未適用の確認

# pendingの一覧を表示
jq '.pending.pro' database/migrations/status.json
# => ["004_add_status_column"]

開発環境で適用したマイグレーションのうち、本番にまだ適用していないものが一目で分かります。

自動更新

マイグレーション適用後、スクリプトが自動的に status.json を更新します。手動で更新する必要がないため、更新忘れを防げます。

💡 実践Tips

Tip 1: 破壊的変更は段階的に

カラム名の変更やテーブル構造の変更は、一度に行わず段階的に実行します。

-- ステップ1: 新しいカラムを追加
ALTER TABLE contents ADD COLUMN new_name TEXT;

-- ステップ2: データを移行
UPDATE contents SET new_name = old_name;

-- ステップ3: 古いカラムを削除(別のマイグレーションで)
ALTER TABLE contents DROP COLUMN old_name;

ステップ2と3の間にアプリケーションの動作確認を挟むことで、問題があっても影響を最小限にできます。

Tip 2: ロールバック用SQLも用意

重要なマイグレーションには、ロールバック用のSQLもコメントで残しておきます。

-- マイグレーション
ALTER TABLE contents ADD COLUMN status TEXT DEFAULT 'draft';

-- ロールバック(必要時のみ実行)
-- ALTER TABLE contents DROP COLUMN status;

Tip 3: Claude Codeとの協働ルール

CLAUDE.mdにマイグレーション運用のルールを明記しています。

## マイグレーション運用

- 直接psqlでSQLを実行しない
- 必ずmigrate.shスクリプト経由で適用
- 本番適用前に開発環境でリハーサル
- 適用後はstatus.jsonをコミット

AIエージェントが誤って直接SQLを実行することを防いでいます。

✅ まとめ

DBマイグレーション運用から得た学びをまとめます。

うまくいっていること:

  • 連番ファイルで時系列管理
  • 開発・本番共通スクリプトでリハーサル
  • status.jsonで適用状況を一元管理
  • 確認フローで誤操作防止

注意が必要なこと:

  • 手動SQL管理は変更量が増えると大変になる可能性
  • 複雑なデータ移行は事前にテストデータで検証
  • ロールバック手順も事前に考えておく

個人開発でも、最初からルールを決めておくことで、後から困ることが少なくなります。

明日は「NextAuth.jsからBetter Authへ:認証ライブラリを移行した理由」について解説します。


シリーズの他の記事

  • 12/7: データベースのID設計:ID方式の選択と主キーの考え方
  • 12/9: NextAuth.jsからBetter Authへ:認証ライブラリを移行した理由
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?