drizzle-sqlite-scaffold について
Drizzle と SQLite の初期設定や、既存プロジェクトへのテーブル・CRUD リポジトリ追加に使うテンプレート型スキルです。設定やスキーマ、コードの規約を統一したい開発者向けです。
主な機能
- 01プロジェクト初期化テンプレート
- 02テーブル別スキーマ・CRUD テンプレート
- 03SQLite ドライバーの選択設定
- 04drizzle-zod バリデーターの任意生成
- 05マイグレーション手順の案内
活用シーン
- 01Drizzle SQLite プロジェクトの開始
- 02既存スキーマへのテーブル追加
- 03既存テーブル用 CRUD モジュールの作成
- 04手書き Drizzle 設定の統一
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ pproenca/ dot-skills --skill drizzle-sqlite-scaffoldインストール後、Claude Code で/drizzle-sqlite-scaffoldを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
config.jsongotchas.mdmetadata.jsonassets/templates/client.better-sqlite3.ts.templateclient.bun-sqlite.ts.templateclient.libsql.ts.templatedrizzle.config.local.ts.templatedrizzle.config.turso.ts.templategitignore.templaterepository.ts.templateschema-index.ts.templatetable.ts.templatevalidators.ts.templatereferences/conventions.md詳細
Drizzle SQLite スキャフォールド
新規プロジェクトで Drizzle + SQLite を初期設定する場合や、既存プロジェクトに新しいテーブル/リポジトリを追加する場合に使える、パラメーター化されたテンプレートです。すべての出力には、references/conventions.md に記載されている規約が反映されます。明示的な主キー、インデックス付き外部キー、relations() 宣言、$inferSelect/$inferInsert のエクスポート、timestamp_ms の日付、ブールモードの真偽値、WAL + foreign_keys=ON + busy_timeout のプラグマ、HMR ガード付きのシングルトンクライアント、.returning() + inArray() + .onConflictDoUpdate() を使った CRUD ヘルパーなどが含まれます。
使用する場合
次のような場合に、これらのテンプレートを利用してください。
- Drizzle と SQLite(任意のドライバー)を使う新規プロジェクトを開始するとき
- 既存の Drizzle プロジェクトに新しいテーブルを追加するとき — テーブルファイルは既存のパターンに合わせてください
- 既存のテーブル用に CRUD リポジトリモジュールを追加するとき
- プラグマが不足している、
relations()がない、または手書きのUser型がスキーマから乖離している、独自実装の Drizzle セットアップをリファクタリングするとき - 別の ORM(Prisma、Kysely)から Drizzle に移行し、最初から一貫した形にしたいとき
セットアップ
必須パラメーター(初回使用時に質問され、config.json に保存されます)
| パラメーター | 必須 | デフォルト | 値 |
|---|---|---|---|
driver | はい | — | better-sqlite3 | libsql | bun-sqlite(D1 はライフサイクルが異なります — 下記の「Cloudflare D1」を参照) |
db_url_env | いいえ | DATABASE_URL | 環境変数名 |
schema_dir | いいえ | ./src/db/schema | テーブルごとのスキーマファイル |
repository_dir | いいえ | ./src/db/repository | テーブルごとの CRUD モジュール |
validators_dir | いいえ | ./src/db/validators | drizzle-zod スキーマ(with_zod=true の場合) |
client_path | いいえ | ./src/db/client.ts | シングルトンクライアントモジュール |
migrations_dir | いいえ | ./drizzle | drizzle-kit の出力先 |
config.json がすでに値を含んでいる場合、このスキルはその値を使用します。そうでない場合は、AskUserQuestion を通じて質問します。
テーブルごとのパラメーター(新しいテーブルをスキャフォールドするたびに質問されます)
| パラメーター | 必須 | デフォルト | 説明 |
|---|---|---|---|
name | はい | — | ケバブケースの単数形:user、order-item。ファイル名と TS 識別子(name_camel、name_pascal を導出)に使用します。 |
table_name | いいえ | name のスネークケース複数形 | SQL テーブル名:users、order_items |
pk | いいえ | serial-int | serial-int | uuid | cuid2 | text |
timestamps | いいえ | true | createdAt/updatedAt 列を追加します |
soft_delete | いいえ | false | NULL 許容の deletedAt + 部分インデックスを追加します |
relations | いいえ | [] | 関連するテーブル名のリスト — relations() の本体を展開します |
with_zod | いいえ | true | drizzle-zod バリデーターのファイルを生成します |
利用可能なテンプレート
プロジェクト初期化テンプレート(一度だけ出力)
| テンプレート | 出力ファイル | 使用条件 |
|---|---|---|
drizzle.config.local.ts.template | drizzle.config.ts | driver が better-sqlite3、bun-sqlite、または file: URL を使う libsql の場合 |
drizzle.config.turso.ts.template | drizzle.config.ts | Turso に接続する libsql の場合(リモートの libsql: URL) |
client.better-sqlite3.ts.template | {{client_path}} | driver が better-sqlite3 の場合 |
client.libsql.ts.template | {{client_path}} | driver が libsql の場合 |
client.bun-sqlite.ts.template | {{client_path}} | driver が bun-sqlite の場合 |
schema-index.ts.template | {{schema_dir}}/index.ts | 常に(初期状態では空で、テーブルの追加に合わせてエクスポートを追記します) |
gitignore.template | .gitignore(追記) | 常に |
テーブルごとのテンプレート(テーブルごとに一度出力)
| テンプレート | 出力ファイル | タイミング |
|---|---|---|
table.ts.template | {{schema_dir}}/{{name}}.ts | テーブルごと |
repository.ts.template | {{repository_dir}}/{{name}}.ts | テーブルごと |
validators.ts.template | {{validators_dir}}/{{name}}.ts | with_zod=true の場合、テーブルごと |
使用方法
フロー A — 新しいプロジェクトを初期化する(一度だけ実行)
-
プロジェクトのパラメーターを解決します。
config.jsonを読み込みます。必須フィールドが空の場合は、AskUserQuestionを通じてユーザーに質問します(厳密に必須なのは driver のみで、他の項目には妥当なデフォルト値があります)。 -
最初にランタイムとツールをインストールします。これにより、生成されたファイルがすぐに型チェックできるようになります:
# Pick the driver-specific runtime package: npm install drizzle-orm @libsql/client # for libsql npm install drizzle-orm better-sqlite3 # for better-sqlite3 npm install drizzle-orm # bun:sqlite is built into Bun # Dev tools (all drivers): npm install -D drizzle-kit npm install -D @types/better-sqlite3 # better-sqlite3 only npm install -D drizzle-zod zod # if with_zod=true -
解決した
driverに応じて、設定とクライアントのバリアントを選択します:better-sqlite3→drizzle.config.local.ts.template+client.better-sqlite3.ts.templatefile:URL を使用するlibsql→drizzle.config.local.ts.template+client.libsql.ts.template- リモートの Turso URL を使用する
libsql→drizzle.config.turso.ts.template+client.libsql.ts.template bun-sqlite→drizzle.config.local.ts.template+client.bun-sqlite.ts.template
-
プロジェクト初期化用ファイルを生成して書き込みます:
drizzle.config.ts{{client_path}}(通常はsrc/db/client.ts){{schema_dir}}/index.ts(空のバレルファイル)gitignore.templateのブロックをプロジェクトの.gitignoreに追加します
-
libsql の場合: クライアントテンプレートではトップレベルの
await migrate(...)を使用しています。トップレベルの await をサポートするため、tsconfig.jsonで"module": "ESNext"(または"NodeNext")と"target": "ES2022"+が設定されていることを確認します。ランタイムが CommonJS の場合は、トップレベルの await を、アプリの起動時に呼び出すエクスポート済みのasync function init()に置き換えます。 -
解決した値を
config.jsonに保存し、以降のテーブル追加時に再度質問されないようにします。
フロー B — 新しいテーブルを追加する(テーブルごとに実行)
-
テーブルごとのパラメーターを解決します。
nameをユーザーに尋ねてから、table_name(snake_case の複数形)、pk、timestamps、soft_delete、relations、with_zodのデフォルト値を提示します。ユーザーがデフォルト以外を希望する項目については、AskUserQuestionを使用します。 -
派生する識別子を計算します:
name_camel—nameの camelCase 形式(user、orderItem)name_pascal—nameの PascalCase 形式(User、OrderItem)pk_field— PK カラム名(4 つのpkモードすべてでid)pk_ts_type— PK の TS 型(serial-intではnumber、uuid/cuid2/textではstring)pk_definition— 実際の行。例:id: integer().primaryKey({ autoIncrement: true }),(以下の PK バリアント表を参照)
-
テーブルテンプレートを生成します:
table.ts.templateを読み込み、{{name}}、{{name_camel}}、{{name_pascal}}、{{table_name}}、{{pk_definition}}、{{pk_extra_imports}}などを置換します。パラメーターに応じて{{timestamps_block}}と{{soft_delete_block}}を展開します(以下の「ブロックの展開」を参照)。{{schema_dir}}/{{name}}.tsに書き込みます。 -
同じパラメーターでリポジトリテンプレートを生成します。
{{repository_dir}}/{{name}}.tsに書き込みます。 -
with_zod=trueの場合は、バリデーターのテンプレートを生成します。{{validators_dir}}/{{name}}.tsに書き込みます。 -
スキーマのバレルファイルに追加します:
{{schema_dir}}/index.tsにexport * from './{{name}}';を追加します。 -
マイグレーションを生成します: SQL ファイルを生成するために
npx drizzle-kit generateを実行するようユーザーに伝えます。このスキャフォールドで、名前の異なる既存のテーブルを置き換える場合は、名前変更の確認プロンプトに明示的に回答するよう念を押します。 -
マイグレーションを適用します: 開発用データベースに対して
npx drizzle-kit migrateを実行します。クライアントテンプレートも起動時にmigrate(...)を呼び出しますが、開発ループで一度適用しておけば、次回のプロセス再起動前に SQL が機能することを確認できます。
フロー C — 既存のテーブルに CRUD モジュールを追加する(スキーマ変更なし)
フロー B の手順 1~2 と同じですが、table.ts.template のレンダリングはスキップし、リポジトリモジュール(および任意でバリデーターモジュール)のみを出力します。
PK のバリエーション
pk の値 | pk_definition | pk_ts_type | 追加のインポート |
|---|---|---|---|
serial-int(デフォルト) | id: integer().primaryKey({ autoIncrement: true }), | number | — |
uuid | id: text().primaryKey().$defaultFn(() => crypto.randomUUID()), | string | —(Web Crypto を使用) |
cuid2 | id: text().primaryKey().$defaultFn(() => createId()), | string | import { createId } from '@paralleldrive/cuid2'; |
text | id: text().primaryKey(), | string | —(呼び出し元が ID を指定) |
プレースホルダーの参照
テンプレートで使用するすべての {{placeholder}} と、その導出ルールです。simple sub の項目は検索して置換し、block の項目は次のセクションのルールに従ってエージェントが展開する必要があります。
| プレースホルダー | 種類 | ソース/導出方法 |
|---|---|---|
{{driver}} | simple sub | config.json:driver |
{{db_url_env}} | simple sub | config.json:db_url_env |
{{schema_dir}} | simple sub | config.json:schema_dir |
{{repository_dir}} | simple sub | config.json:repository_dir |
{{validators_dir}} | simple sub | config.json:validators_dir |
{{client_path}} | simple sub | config.json:client_path |
{{migrations_dir}} | simple sub | config.json:migrations_dir |
{{schema_index_import}} | simple sub | 導出:client_path から {{schema_dir}}/index.ts への相対パス(通常は './schema') |
{{client_import}} | simple sub | 導出:リポジトリ内のファイルから client_path への相対パス(通常は '../client') |
{{schema_import}} | simple sub | 導出:リポジトリまたはバリデーターのファイルから該当するテーブルファイルへの相対パス(通常は '../schema/{{name}}') |
{{name}} | simple sub | テーブルごとのパラメーター — ケバブケースの単数形(user) |
{{name_camel}} | simple sub | name から導出(user、orderItem) |
{{name_pascal}} | simple sub | name から導出(User、OrderItem) |
{{table_name}} | simple sub | テーブルごとのパラメーター。デフォルトは name のスネークケース複数形(users、order_items) |
{{pk}} | metadata | テーブルごとのパラメーター — serial-int | uuid | cuid2 | text(以下の行を決定します) |
{{pk_definition}} | block | 実際の PK カラム行 — 「PK バリアント」表を参照 |
{{pk_field}} | simple sub | このスキルで提供される4つの PK バリアントでは常に id |
{{pk_ts_type}} | simple sub | serial-int の場合は number、uuid/cuid2/text の場合は string |
{{pk_extra_imports}} | block | serial-int/uuid/text の場合は空。cuid2 の場合は import { createId } from '@paralleldrive/cuid2'; |
{{relation_imports}} | block | relations[] 内の各テーブルについて、import { {{relatedCamel}} } from './{{related-kebab}}'; を出力 |
{{domain_columns}} | block | エンティティの実際の、PK でもタイムスタンプでもないカラムに置き換えます。ユーザーから情報が提供されていない場合は、TODO コメントのままにします。 |
{{timestamps_block}} | block | 下記の展開方法を参照 — timestamps=true の場合に出力し、false の場合は行全体を削除 |
{{soft_delete_block}} | block | 下記の展開方法を参照 — soft_delete=true の場合にカラムブロック内へ出力 |
{{indexes}} | block | 外部キーのカラムごとに1行の index(...) を出力(およびユーザーが指定した (authorId, publishedAt) 形式の複合インデックス) |
{{soft_delete_index}} | block | deletedAt に対する部分インデックス(下記の展開方法を参照)。soft_delete=true の場合のみ出力 |
{{relations_body}} | block | 関連テーブルごとに1行の one(...)/many(...) を出力。下記の展開方法を参照 |
{{insert_refinements}} | block | INSERT 形式の drizzle-zod リファインメントコールバック。指定がない場合はサンプルコメントを残す |
{{update_refinements}} | block | 部分 UPDATE 形式について同様に処理 |
{{exports}} | block | schema-index.ts.template 内で、テーブルごとに export * from './{{name}}'; の行を出力。新しいテーブルを追加するたびに追記 |
テンプレートがこの表にない {{placeholder}} を出力する場合はバグです。gotchas.md に報告してください。
ブロックの展開
table.ts.template では、形状が可変のセクションにプレースホルダーのブロックを使用します。エージェントは単にテキスト置換するのではなく、パラメーターに従って展開する必要があります。
{{timestamps_block}}(timestamps=true の場合)
createdAt: integer({ mode: 'timestamp_ms' })
.notNull()
.$defaultFn(() => new Date()),
updatedAt: integer({ mode: 'timestamp_ms' })
.notNull()
.$defaultFn(() => new Date())
.$onUpdateFn(() => new Date()),
timestamps=false の場合は、行全体を削除します(コメントマーカーを残さないでください)。
{{soft_delete_block}}(soft_delete=true の場合)
カラムブロック内:
deletedAt: integer({ mode: 'timestamp_ms' }),
インデックスブロック内:
index('{{table_name}}_active_idx').on(table.deletedAt).where(sql`deleted_at IS NULL`),
それに応じて sql のインポートを調整してください。
{{relations_body}}(relations が空でない場合)
relations[] の関連テーブルごとに、エージェントは、FK が現在のテーブルにある場合は one、関連テーブルにある場合は many と判断します。
// FK on current table — `one`:
parent: one(parents, { fields: [users.parentId], references: [parents.id] }),
// FK on related table — `many`:
posts: many(posts),
ユーザーが簡単に判断できない場合は、それぞれの例を 1 つずつ使用し、コメントを残してください。
{{indexes}} ブロック
各 FK カラムについて、次を出力します。
index('{{table_name}}_{{column}}_idx').on(table.{{columnCamel}}),
Cloudflare D1 に関する注意
D1 のライフサイクルは異なります。クライアントはモジュールレベルのシングルトンとしてではなく、env.DB(バインディング)からリクエストごとに構築されます。このスキルには D1 クライアントのテンプレートは含まれていません。配線については、公式の D1 + Drizzle ガイドに従ってください。table.ts.template、repository.ts.template、validators.ts.template は D1 でも引き続き使用できます。異なるのはクライアントモジュールのみです。
参照ファイル
| ファイル | 説明 |
|---|---|
| references/conventions.md | 適用される 11 の規約と、その理由およびルールへの相互参照 |
| gotchas.md | 時間をかけて明らかになったエッジケース |
| metadata.json | バージョンとドライバーの参照情報 |
| config.json | プロジェクトレベルのパラメーターストア |
関連スキル
drizzle-sqlite— これらのテンプレートに反映されているライブラリ参照ルールです。規約ドキュメントでは、このスキル内の特定のルールファイルを参照しています。十分な情報に基づいて例外を設ける場合、生成されたファイルをデバッグする場合、またはテンプレートの対象範囲外のもの(カスタムマイグレーション、複雑なクエリ、パフォーマンス関連の作業)をスキャフォールドする場合に参照してください。better-auth-scaffold— Drizzle DB 上に Better Auth をスキャフォールドします。このスキルがクライアントを提供した後に実行できます。