本文へ移動
cccskills
無料GitHub で公開日本語紹介

db-migrations

Drizzleのマイグレーション生成からSQLの冪等化、オンライン索引作成、データ補完、開発中の再生成やrebase競合まで、DB変更の進め方を整理します。

原文原文の説明を見る

Use for Drizzle migration rollout, online indexes, backfills, idempotent SQL and migration regeneration or rebase conflicts.

lobehub/lobehubスター 83,504(GitHub 83,504 + cccskills 0)
連携ツールPostgreSQL

実行スコア 未検証

インストール方法を見る

こんなときに便利

  • DBスキーマ変更の展開方法を決めたいとき
  • 大きなテーブルに索引を追加したいとき
  • 既存データの補完処理を設計したいとき
  • rebase後にマイグレーションを再生成したいとき

日本語での紹介

できること

Drizzleを使うデータベース変更について、スキーマの設計、マイグレーション生成、SQLのレビュー、展開方法を整理します。通常のスキーマ変更、書き込みへの影響を抑えるオンライン索引作成、既存データを更新するバックフィルを分け、変更の性質に応じた進め方を示します。生成されたSQLに再実行可能な句を加える方法や、ファイル名とジャーナルの整合、開発中の下書きマイグレーションの再生成、rebase時の競合処理も扱います。展開手順を決める際には、実際の開発用DBで操作を測定し、確認できた範囲と本番への推測を区別する方針です。

こんなときに便利

テーブルや列を追加するとき、既存データを安全に埋めたいとき、大きなテーブルへの索引追加を検討するときに役立ちます。開発中にスキーマが変わった場合や、複数のマイグレーションがrebaseで競合した場合にも、生成物を揃え直す手順を確認できます。

使い方の例

  • 「このスキーマ変更に合う展開方法を整理して」
  • 「既存データの補完を再実行可能なバックフィルに分けて」
  • 「rebase後のスキーマからマイグレーションを作り直して」

注意点

Drizzleの生成手順として bun run db:generate を案内しています。索引の CONCURRENTLY 作成はトランザクション内で実行しません。出荷済みまたは既定ブランチに入ったマイグレーションは書き換えず、後続のマイグレーションで変更します。

この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。

資料チェック

SKILL.md の記述から、注意が要る操作と導入の前提を AI が確認しました。点数は実際に動かした結果(実行検証)だけで付けています。

安全面送信・削除・コマンド実行などの扱いが明示されているか
B一部不足一時DBオブジェクトの除去を求めますが、下書きマイグレーションの削除手順も示します。
導入のしやすさ必要なツールや API キーが少ないか、書かれているか
B一部不足Drizzleと`bun run db:generate`に加え、承認済みDB接続手段が必要です。

点数には入れていません。 2026年10月26日 時点で AI(OpenAI Codex)が判定しました。目安なので、入れる前に原文も確認してください。

評価が違うと思ったら、見直しを依頼する

どの項目が、なぜ違うと思うかを書いてください。ログインは不要です。内容を SKILL.md と照らし合わせて評価を作り直し、この欄に反映します。

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

含まれるファイル(1)

  • SKILL.md13.6 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Database Migrations Guide

Schema conventions

Apply these before generating any migration — they change what the schema file looks like, not just the SQL.

  • No pg enums (and no fixed value sets) for growing domains. For columns whose value set will keep expanding (resource types, statuses, providers, …), use a plain text column typed via .$type<UnionType>(). pgEnum requires an ALTER TYPE ... ADD VALUE migration for every new literal, and even the Drizzle text('col', { enum: [...] }) option hardwires the value list into the schema file. With .$type<>(), onboarding a new value is a type-only change — no migration at all.

    // ✅ Good — type lives in @lobechat/types, column stays plain text
    resourceType: text('resource_type').$type<TransferResourceType>().notNull(),
    
    // ❌ Bad — pg enum, needs ALTER TYPE per new value
    resourceType: resourceTypeEnum('resource_type').notNull(),
    
    // ❌ Avoid — value list hardwired into the schema file
    resourceType: text('resource_type', { enum: TRANSFER_RESOURCE_TYPES }).notNull(),
    
  • Keep domain constants out of schema files. In new or modified schema files under packages/database/src/schemas/, shared domain literal arrays, union types, and option interfaces belong in @lobechat/types (one module per domain, re-exported from its index.ts); both the schema (.$type<>()) and consumers (routers via z.enum(...), services, UI) import from there. This rule targets domain constants only — table objects, inferred row types, Drizzle relation objects, and zod insert/select schemas (insertAgentSchema, …) are the schema file's job and stay put. Existing schema files that already export such constants (e.g. resourcePermission.ts) are grandfathered; migrate them opportunistically when the file is next touched, not in bulk.

  • Prefixed ids only for rows that are addressed one at a time. An idGenerator prefix (task_, cmt_, brf_) earns its keep when the id turns up somewhere a person reads it — a URL segment, an API argument, a tool-call payload, a support ticket. A child table whose rows are only ever fetched in bulk for their parent takes a plain uuid instead, like task_dependencies / task_documents / task_topics; there the prefix costs a registry entry in idGenerator.ts and buys nothing back.

    // ✅ Addressed individually — deleteComment(commentId), /task/:id
    id: text('id')
      .primaryKey()
      .$defaultFn(() => idGenerator('taskComments'))
      .notNull(),
    
    // ✅ Only ever read in bulk for one parent
    id: uuid('id').defaultRandom().primaryKey().notNull(),
    
  • Column order: identity → scope → the table's own columns → visibility → timestamps. Put id and the parent FK first, then the ownership columns (user_id, workspace_id), then whatever this table is actually for, then visibility, then the ...timestamps / createdAt() spread. A reader scanning an unfamiliar table then finds the same field in the same place. visibility sitting at the end is the deliberate slot, not an accident of history: of the 22 tables that carry the column today, 17 place it in the last three columns and none place it directly after id. A new table that hoists it to the front becomes the one outlier — if the placement is ever worth changing, change it repo-wide and update this rule, not one table at a time.

Choose the rollout strategy

Classify every database change into one of these three rollout paths before generating or editing a migration.

Validate rollout assumptions on the actual Dev database

Do not choose a rollout path from hypothetical claims such as “this migration might be slow” or “installing these triggers could block deployment.” Before deciding that a schema change needs a manual production step, deferred installation, or a dedicated backfill, test the relevant operation against the project's actual Dev database.

  • Classify the database target first using the project's approved database-access tooling; never read secret-bearing .env files directly.
  • Measure the real operation or the closest safe equivalent, such as creating an identically defined probe index under a temporary name or installing temporary triggers inside a transaction that is rolled back.
  • Record the tested SQL or operation, representative row count and table size, elapsed time, and cleanup verification.
  • Keep probes reversible and remove every temporary database object after the measurement.
  • Treat a single Dev result as evidence about the observed Dev scale, not proof of production behavior. State material differences in production scale, load, cache state, and lock contention explicitly, and label any resulting production claim as an inference.

Rollout decisions must combine repository deployment facts with these measurements. Do not add operational tables, delayed activation paths, or manual release steps solely to guard against unmeasured performance concerns.

1. Regular Drizzle migration

Use the normal Drizzle workflow for schema changes that are safe to execute during deployment, such as creating a small table or adding a nullable column:

  1. Update the Drizzle schema.
  2. Run bun run db:generate.
  3. Review and harden the generated artifacts using the steps below.

Before listing a manual migration command as a release step, inspect the target repository's build and deployment scripts. If its deployment pipeline already applies migrations automatically, do not require a redundant manual run.

2. Online index creation

Creating an index normally can block writes and queries on a large or frequently accessed table, and a long-running statement can also stall the deployment. In that case:

  1. Before deploying the application, execute the index creation manually in the target database's SQL editor using CONCURRENTLY:

    CREATE INDEX CONCURRENTLY IF NOT EXISTS "table_column_idx"
    ON "table" USING btree ("column");
    
  2. Keep an idempotent, non-CONCURRENTLY version in the Drizzle migration:

    CREATE INDEX IF NOT EXISTS "table_column_idx"
    ON "table" USING btree ("column");
    

The manual online operation avoids blocking production traffic. When the deployment later runs the migration, IF NOT EXISTS makes the statement a no-op, while new or self-hosted databases can still converge through normal migration replay. Do not place CREATE INDEX CONCURRENTLY inside a transaction.

3. Data backfill

Backfills and historical-data reconciliation must run as dedicated, idempotent scripts rather than inside a Drizzle migration. Keep the schema change in Drizzle, but move row-by-row or batch data processing into a separate script so it does not block deployment.

Decide whether to run the script before or after the application deployment based on compatibility:

  • Run it before deployment when the new code or a new constraint requires existing rows to be populated immediately.
  • Run it after deployment when the application safely handles both old and new row shapes and the backfill can converge gradually.

Backfill scripts should be resumable, safe to retry, processed in bounded batches, and observable. Treat optional cleanup or eager reconciliation as optional rather than as a release blocker.

Development-stage schema changes

Schema changes churn during feature development. When the schema changes before the migration has shipped, do not hand-edit the existing migration SQL to chase the new schema shape. Delete the draft migration artifacts added by this branch (SQL file, matching snapshot, and matching journal entry), then run the generator again and re-apply the normal migration review steps below.

For example, if this branch's draft migration is NNNN_add_verify_tables (substitute the branch's real number — never an already-shipped migration):

# 1. Delete the draft SQL and its snapshot
rm packages/database/migrations/NNNN_add_verify_tables.sql
rm packages/database/migrations/meta/NNNN_snapshot.json

# 2. Remove the matching NNNN entry from the journal's "entries" array
#    packages/database/migrations/meta/_journal.json

# 3. Regenerate from the current schema
bun run db:generate

This keeps the generated SQL, snapshot, and journal aligned with the actual schema. Manual SQL edits are reserved for review-time hardening such as idempotent clauses, custom extension SQL, and meaningful filename/tag updates.

Before release, if a feature branch accumulated multiple development-only migrations, consolidate them into one migration when possible. Production does not need to replay every intermediate draft shape, and fewer migrations reduce deploy-time risk.

For example, if this branch added three drafts AAAA, BBBB, and CCCC, delete all three and regenerate a single migration:

# 1. Delete every draft SQL and snapshot this branch added
rm packages/database/migrations/{AAAA,BBBB,CCCC}_*.sql
rm packages/database/migrations/meta/{AAAA,BBBB,CCCC}_snapshot.json

# 2. Remove those entries from the journal's "entries" array
#    packages/database/migrations/meta/_journal.json

# 3. Regenerate one migration covering the full schema delta
bun run db:generate

Do not make a migration compatible with earlier development-only versions of the same branch. While the migration has not shipped, there is no production history to preserve. Fix local/dev databases directly with whatever SQL is simplest (drop the draft table, rename a column, delete draft rows), then regenerate the branch migration from the current schema.

For example, if an earlier draft on this branch created signup_attempt_id and you have since renamed it to user_signup_log_id, do not add a compatibility ALTER ... RENAME to the migration. Just fix the dev DB directly, then regenerate:

# Fix the dev DB to match the new schema (simplest SQL wins)
set -a && source .env && set +a && bun -e '
import pg from "pg";
const client = new pg.Client({ connectionString: process.env.DATABASE_URL });
await client.connect();
await client.query("ALTER TABLE user_signup_logs DROP COLUMN signup_attempt_id");
await client.end();
'

# Regenerate so the migration reflects only the final shape
bun run db:generate

After a migration has reached production or the target default branch, treat it as immutable: add a follow-up migration instead of rewriting it.

Rebase conflicts

When a rebase conflicts in migration files, keep the upstream/default-branch migrations and remove all migrations introduced by the current feature branch. Complete the rebase, then regenerate this branch's migration from the rebased schema. This avoids merging two independent snapshots or hand-splicing journal entries.

Step 1: Generate Migrations

bun run db:generate

This generates:

  • packages/database/migrations/0046_meaningless_file_name.sql

And updates:

  • packages/database/migrations/meta/_journal.json
  • docs/development/database-schema.dbml

Custom Migrations (e.g. CREATE EXTENSION)

For migrations that don't involve Drizzle schema changes (e.g. enabling PostgreSQL extensions), use the --custom flag:

bunx drizzle-kit generate --custom --name=enable_pg_search

This generates an empty SQL file and properly updates _journal.json and snapshot. Then edit the generated SQL file to add your custom SQL:

-- Custom SQL migration file, put your code below! --
CREATE EXTENSION IF NOT EXISTS pg_search;

Do NOT manually create migration files or edit _journal.json — always use drizzle-kit generate to ensure correct journal entries and snapshots.

Step 2: Optimize Migration SQL Filename

Rename auto-generated filename to be meaningful:

0046_meaningless_file_name.sql → 0046_user_add_avatar_column.sql

Step 3: Use Idempotent Clauses (Defensive Programming)

Always use defensive clauses to make migrations idempotent (safe to re-run):

CREATE TABLE

-- ✅ Good
CREATE TABLE IF NOT EXISTS "agent_eval_runs" (
  "id" text PRIMARY KEY NOT NULL,
  "name" text,
  "created_at" timestamp with time zone DEFAULT now() NOT NULL
);

-- ❌ Bad
CREATE TABLE "agent_eval_runs" (...);

ALTER TABLE - Columns

-- ✅ Good
ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "avatar" text;
ALTER TABLE "posts" DROP COLUMN IF EXISTS "deprecated_field";

-- ❌ Bad
ALTER TABLE "users" ADD COLUMN "avatar" text;

ALTER TABLE - Foreign Key Constraints

PostgreSQL has no ADD CONSTRAINT IF NOT EXISTS. Use DROP IF EXISTS + ADD:

-- ✅ Good: Drop first, then add (idempotent)
ALTER TABLE "agent_eval_datasets" DROP CONSTRAINT IF EXISTS "agent_eval_datasets_user_id_users_id_fk";
ALTER TABLE "agent_eval_datasets" ADD CONSTRAINT "agent_eval_datasets_user_id_users_id_fk"
  FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;

-- ❌ Bad: Will fail if constraint already exists
ALTER TABLE "agent_eval_datasets" ADD CONSTRAINT "agent_eval_datasets_user_id_users_id_fk"
  FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;

DROP TABLE / INDEX

-- ✅ Good
DROP TABLE IF EXISTS "old_table";
CREATE INDEX IF NOT EXISTS "users_email_idx" ON "users" ("email");
CREATE UNIQUE INDEX IF NOT EXISTS "users_email_unique" ON "users" USING btree ("email");

-- ❌ Bad
DROP TABLE "old_table";
CREATE INDEX "users_email_idx" ON "users" ("email");

Step 4: Update Journal Tag

After renaming the migration SQL file in Step 2, update the tag field in packages/database/migrations/meta/_journal.json to match the new filename (without .sql extension).

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

acceptance

無料概要あり

実際の製品を操作して、利用者が確認できる動作証拠を集め、検証計画に沿った受け入れレポートとして公開するスキルです。

  • 変更後の製品動作を実地で検証したいとき
  • 画面キャプチャなどの証拠を集めたいとき
  • 検証計画とレポートを作成したいとき
lobehub/lobehub8.4万2026年10月26日 更新

add-model-provider

無料概要あり

LobeHubにAIモデルプロバイダーを追加し、実行時連携からモデル表示、設定、ブランド表記、文書化、動作確認まで進めるスキルです。

  • 新しいAIモデルプロバイダーを追加したいとき
  • プロバイダーの設定手順や説明文を更新したいとき
  • 既存プロバイダーへのモデル追加要件を見極めたいとき
lobehub/lobehub8.4万2026年10月26日 更新

add-setting-env

無料概要あり

ユーザー設定の初期値をサーバー側の環境変数で切り替えるため、型定義や設定の組み立て、ユーザーストアへの反映、環境変数の例と説明書きを追加する手順です。

  • 設定の初期値を環境変数で変えたいとき
  • 設定項目をサーバー設定に追加したいとき
  • 環境変数の例と説明を更新したいとき
lobehub/lobehub8.4万2026年10月26日 更新

agent-runtime-hooks

無料概要あり

エージェント実行中の各段階をフックで監視し、ツール呼び出しの模擬・制御や人の承認、圧縮、サブエージェント処理に介入する仕組みを扱います。

  • エージェントの実行状況を記録したいとき
  • ツール結果をテスト用に模擬したいとき
  • Webhookでツール実行を許可・拒否したいとき
lobehub/lobehub8.4万2026年10月26日 更新

agent-signal

無料概要あり

イベントを起点にエージェントのバックグラウンド処理を組み立て、ソース・シグナル・アクション・ポリシーの役割分担や非同期連携を実装するためのスキルです。

  • イベント起点の処理を追加したいとき
  • バックグラウンド処理を非同期化したいとき
  • 重複実行を防ぐ仕組みを整えたいとき
lobehub/lobehub8.4万2026年10月26日 更新

agent-testing-bot

無料概要あり

DiscordやSlackなどの実際のチャットアプリでボットにメッセージを送り、応答を画面で確認する受け入れテストを行うスキルです。

  • 実際のDiscordでボット応答を確かめたいとき
  • SlackやTelegramの会話経路をテストしたいとき
  • macOSアプリ上の操作結果を画面で記録したいとき
lobehub/lobehub8.4万2026年10月26日 更新

lobehub のスキルをすべて見る

このスキルの問題を報告する