Drizzle ORMは、TypeScriptでテーブルを定義し、SQLとほぼ同じ形のクエリを型安全に書けるORMです。読み方は「ドリズル」。2026年9月26日時点のnpmでは、latestタグが0.45.3(2026年9月21日公開)、rcタグが1.0.0-rc.4(2026年6月27日公開)で、安定版とv1候補版が並行しています。
本記事では、両方の版をPGlite(WASM版PostgreSQL)で実際に動かし、インストールからCRUD・JOIN、drizzle-kitによるマイグレーション、v1への移行手順、Prismaとの選び分けまでをまとめます。基本操作のコードは0.45.3とPGlite用ドライバで検証し、掲載時に接続部分をnode-postgres向けへ変更しています。v1移行の例は1.0.0-rc.4が対象です。
まとめ:Drizzle ORMの要点と2026年9月時点の版
- Drizzle ORMはTypeScriptで書かれたORMで(JavaScriptからも使えます)、
select().from().where()のようにSQLの語順で書け、戻り値の型がスキーマから推論されます。drizzle-ormパッケージのランタイム依存(dependencies)は0件で、公式READMEはminify+gzip後の大きさを約7.4KBとしています。 - 本番で使う安定版は0.45.3(drizzle-kitは0.31.11)です。1.0はRC段階で、リレーション定義・マイグレーションフォルダの形式・casing指定に破壊的変更があります。
- マイグレーションは「
drizzle-kit generateでSQLを生成し、migrateで適用」が基本です。pushはSQLファイルを生成せずDBへ直接反映する方式で、ダウンマイグレーション(自動ロールバック)の仕組みはありません。 - Prismaとの差は、スキーマをTypeScriptで書くか専用DSLで書くか、SQLをどこまで見せるかです。SQLを把握したいチームやエッジ環境ではDrizzle、専用DSLと生成クライアントを中心にした開発フローを求めるならPrismaが向きます。
- where句を付け忘れた
update()は全行を更新します。drizzle-kit 0.31.11では列名の変更をgenerateが対話で確認するため、CIのような非TTY環境では失敗します。
Drizzle ORMの定義と読み方・現行バージョン
読み方「ドリズル」と名前の意味
drizzleは英語で「霧雨」を意味し、発音はカタカナで「ドリズル」です。開発元はDrizzle Team、ライセンスはApache-2.0で、GitHubのdrizzle-team/drizzle-ormはスター数約3.6万(2026年9月26日時点)です。公式サイトはorm.drizzle.teamで、ドキュメントもここにあります。
ORM(Object-Relational Mapping)は、データベースのテーブルとプログラムのオブジェクトを対応づけ、SQLを直接書かずに読み書きできるようにする仕組みです。Drizzleはその中でも抽象化を薄くとる設計で、発行されるSQLをtoSQL()でそのまま確認できます。
安定版0.45系とv1.0 RCの位置づけ
| 項目 | 0.45系(安定版) | 1.0 RC |
|---|---|---|
| npmタグ | latest=0.45.3 | rc=1.0.0-rc.4 |
| 公開日 | 2026年9月21日 | 2026年6月27日 |
| drizzle-kit | 0.31.11 | 1.0.0-rc.4 |
| リレーション定義 | relations() | defineRelations() |
| マイグレーション出力 | 連番SQL+meta/_journal.json | タイムスタンプ付きフォルダ |
| バリデータ連携 | drizzle-zod等の別パッケージ | drizzle-orm/zod等を同梱 |
インストールコマンドにタグを付けなければ0.45系が入ります。v1を試すならnpm i drizzle-orm@rc drizzle-kit@rcのように明示します。業務システムでは、RCが外れるまで0.45系を使い、v1の差分は検証用ブランチで確かめる進め方が安全です。
対応データベースとドライバ
0.45.3のパッケージにはPostgreSQL・MySQL・SQLite・SingleStore・Gelのコア(pg-coreなど)が入っています。1.0 RCではMSSQL(SQL Server、mssqlドライバ)とCockroachDBが加わりました。なお1.0.0-rc.4のnpmパッケージにはgel関連のディレクトリが無く、Gelを使うなら0.45系のままにします。ドライバはnode-postgres・postgres.js・Neon・Supabase・PlanetScale・Turso(libSQL)・Cloudflare D1・Bun SQLiteなどに対応し、0.45.3ではNetlify DBドライバが追加されました。
Pythonなど他言語向けの版はありません。「drizzle python」で探しているなら、SQLAlchemyのようなPython向けORMが代わりになります。
インストールからdrizzle.config.tsまでの導入手順
パッケージのインストール
PostgreSQLをnode-postgresで使う場合の構成です。drizzle-ormは本体、drizzle-kitはマイグレーション用CLIなので開発依存に入れます。
npm i [email protected] pg
npm i -D [email protected] @types/pg
バージョンを指定しないと、v1がlatestになった時点でv1が入り、本記事のrelations()の書き方が動かなくなります。接続先はDATABASE_URLのような環境変数で渡し、接続文字列をコードに書かないようにします。Supabaseと組み合わせる場合の接続文字列の選び方は、SupabaseにPrismaとDrizzleをつなぐ:接続文字列とマイグレーション二重管理の設計で扱っています。
スキーマ定義(テーブル・外部キー・インデックス)
テーブルはTypeScriptの関数で定義します。以下はusersとpostsの1対多で、postsのauthor_idに外部キーとインデックスを付けています。
// src/schema.ts
import { pgTable, serial, text, integer, timestamp, index } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
createdAt: timestamp('created_at').defaultNow().notNull(),
});
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
title: text('title').notNull(),
authorId: integer('author_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
}, (t) => [index('posts_author_idx').on(t.authorId)]);
// リレーショナルクエリ(with)用の関係定義。0.45系の書き方
export const usersRelations = relations(users, ({ many }) => ({ posts: many(posts) }));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));
references()はDB上の外部キー制約を作り、relations()はクエリ時の関連づけだけを定義します。withによる関連取得に必要なのはrelations()で、外部キー制約のreferences()は必須ではありません。参照整合性をDBで守りたいならreferences()も付けます。
drizzle.config.tsの必須項目
// drizzle.config.ts
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
dialect: 'postgresql',
schema: './src/schema.ts',
out: './drizzle',
dbCredentials: { url: process.env.DATABASE_URL! },
});
公式ドキュメントが最低限必要とするのはdialectとschemaの2つで、outは省略するとdrizzleフォルダになります。dialectは0.31.11ではpostgresql・mysql・sqlite・turso・singlestore・gelから選びます。dbCredentialsはmigrate・push・pull・studioが使う接続情報で、generateだけならDBに接続しません。
基本操作:CRUD・JOIN・リレーショナルクエリ
作成・取得・更新・削除(CRUD)
実行前にPostgreSQLのデータベースを用意してDATABASE_URLを設定し、npx drizzle-kit generate、npx drizzle-kit migrateの順に実行してテーブルを作成しておきます。以下は空のテーブルで実行する例です。
import { drizzle } from 'drizzle-orm/node-postgres';
import { eq } from 'drizzle-orm';
import * as schema from './schema';
import { users } from './schema';
const db = drizzle({ connection: process.env.DATABASE_URL!, schema });
// Create:returning() で挿入後の行を受け取る(PostgreSQL・SQLite)
const [alice] = await db.insert(users).values({ name: 'Alice', email: '[email protected]' }).returning();
// Read:選んだ列だけが型に残る
const rows = await db.select({ id: users.id, name: users.name }).from(users).where(eq(users.email, '[email protected]'));
// Update:where を必ず付ける
await db.update(users).set({ name: 'Alice2' }).where(eq(users.id, alice.id));
// Delete
await db.delete(users).where(eq(users.id, alice.id));
PGliteで実行すると、rowsは[ { id: 1, name: 'Alice' } ]でした。postsの外部キーにonDelete: 'cascade'を付けているため、usersの行を消すとその人のpostsも消えます。
JOINと集計のSQL確認
import { count, desc, eq } from 'drizzle-orm';
import { posts } from './schema';
// CRUD例の後、JOIN用のデータを登録する
const [a] = await db.insert(users).values({ name: 'Alice', email: '[email protected]' }).returning();
await db.insert(users).values({ name: 'Bob', email: '[email protected]' });
await db.insert(posts).values([{ title: 'p1', authorId: a.id }, { title: 'p2', authorId: a.id }]);
const q = db
.select({ name: users.name, n: count(posts.id) })
.from(users)
.leftJoin(posts, eq(posts.authorId, users.id))
.groupBy(users.id)
.orderBy(desc(count(posts.id)));
console.log(q.toSQL().sql);
const result = await q; // [ { name: 'Alice', n: 2 }, { name: 'Bob', n: 0 } ]
toSQL()が返したSQLはselect "users"."name", count("posts"."id") from "users" left join "posts" on "posts"."author_id" = "users"."id" group by "users"."id" order by count("posts"."id") descで、書いたメソッドチェーンと1対1で対応します。innerJoin・rightJoin・fullJoinも同じ形で書けます。
withによるリレーショナルクエリ
const list = await db.query.users.findMany({
columns: { name: true },
with: { posts: { columns: { title: true } } },
});
// [{"name":"Alice","posts":[{"title":"p1"},{"title":"p2"}]},{"name":"Bob","posts":[]}]
JOINの例で登録したデータに対する結果です。ネストしたJSONをそのまま返したいときはdb.queryを使います。drizzle()にschemaを渡していないとdb.query.usersが型に現れません。
drizzle-kitのコマンドとマイグレーション運用
generate・migrate・push・pull・check・studioの役割
| コマンド | 処理 | DB接続 |
|---|---|---|
| generate | スキーマ差分からSQLを生成 | 不要 |
| migrate | 未適用のSQLを適用 | 必要 |
| push | スキーマをDBへ直接反映 | 必要 |
| pull | 既存DBからスキーマを生成 | 必要 |
| check | マイグレーション履歴の整合を検査 | 不要 |
| studio | ブラウザでデータを閲覧・編集 | 必要 |
| up | 古い形式のスナップショットを更新 | 不要 |
0.31.11の--helpでは、既存DBからの取り込みがintrospect、履歴の削除がdropという名前で残っています。1.0.0-rc.4の--helpではintrospectがpullに統一され、dropは一覧から消えました。
本番のgenerate・migrateと試作のpushの使い分け
最初のスキーマでnpx drizzle-kit generateを実行すると、0.31.11ではdrizzle/0000_<ランダム名>.sqlとdrizzle/meta/_journal.jsonなどが生成されました。SQLには--> statement-breakpointの区切りが入り、外部キーはALTER TABLE ... ADD CONSTRAINTで後から付けられます。
生成されたSQLはレビューしてからコミットし、デプロイ時にdrizzle-kit migrate、またはアプリ側でmigrate(db, { migrationsFolder: './drizzle' })を呼んで適用します。公式ドキュメントはpushを「rapid prototyping」に最適な方法と説明しつつ、本番でも主要なマイグレーション手段として使うチームがあると紹介しています。それでもpushは履歴を残さずにDBを書き換えるので、複数環境で同じ変更を再現する必要がある本番DBには使わないのが無難です。
ロールバック(down migration)が無い前提での戻し方
drizzle-kitにはdownマイグレーションを生成・適用する機能がありません。GitHubの機能要望「Reverse/Down Migrations」(issue #4005、2025年1月起票)は2026年9月26日時点でもOpenです。戻すときは、スキーマを元の形に直してgenerateを再実行し、逆向きのSQLを新しいマイグレーションとして積みます。削除した列のデータは戻らないため、列削除を含む変更の前にはバックアップを取ります。
Supabase CLIのdb diffでマイグレーションを管理している場合は、どちらを正とするかを先に決めます。両方で履歴を持つと二重管理になります(Supabase CLIとローカル開発環境:db diffで進めるマイグレーションとCI)。
v1.0 RCへの移行:変更点とdrizzle-kit up
relations()からdefineRelations()への書き換え
v1ではリレーション定義が「Relational Queries v2」に変わり、スキーマ全体を1か所で宣言します。1.0.0-rc.4には旧来のrelations()が無いため、先ほどのschema.tsからrelationsのimportとusersRelations・postsRelationsを削除し、テーブル定義だけを残します。そのうえで次のrelations.tsを追加し、1.0.0-rc.4でAliceと投稿を取得できることを確認しました。
// src/relations.ts(1.0 RC)
import { defineRelations } from 'drizzle-orm';
import * as schema from './schema';
export const relations = defineRelations(schema, (r) => ({
users: { posts: r.many.posts() },
posts: { author: r.one.users({ from: r.posts.authorId, to: r.users.id }) },
}));
// src/db.ts:drizzle() には schema ではなく relations を渡す
import { drizzle } from 'drizzle-orm/node-postgres';
import { relations } from './relations';
const db = drizzle({ connection: process.env.DATABASE_URL!, relations });
await db.query.users.findMany({ with: { posts: true }, where: { name: 'Alice' } });
whereがコールバックではなくオブジェクトで書ける点も変わりました。rc.1のリリースノートは、PostgreSQLで旧API(._query)を削除したことと、casing指定をテーブル定義側(snakeCase.table()など)へ移した破壊的変更を告知しています。
マイグレーションフォルダの新形式とdrizzle-kit up
1.0.0-rc.4でgenerateすると、drizzle/20260926050716_stormy_war_machine/migration.sqlと同じフォルダのsnapshot.jsonが作られ、_journal.jsonは生成されませんでした。0.31.11で作ったdrizzleフォルダに1.0.0-rc.4のdrizzle-kit upをかけると、同じ新形式へ変換されました。
既存プロジェクトをv1へ上げる手順は、(1)0.45系で未生成の差分が無い状態にする、(2)drizzle-ormとdrizzle-kitを同じRC版にそろえる、(3)drizzle-kit upで履歴を変換する、(4)relations()をdefineRelations()へ書き換える、の順です。(3)の前にdrizzleフォルダをコミットしておけば、変換結果を差分で確認できます。
drizzle-kit skillsとmcp:AIエージェント向けの新コマンド
1.0.0-rc.4のdrizzle-kitにはskillsとmcpの2コマンドがあり、0.31.11にはありません。skillsはパッケージに同梱された8個のAgent Skills(drizzle・drizzle-generate・drizzle-migrations・drizzle-push・drizzle-pullなど)を、skills@latest add経由でAIコーディングエージェントに追加します。mcpはMCPサーバーを起動するコマンドです。
各スキルはSKILL.md形式で、エージェントがDrizzleのファイルやdrizzle-kitの出力を扱う前に読む手順書になっています。SKILL.mdの仕様はAgent Skillsとは?SKILL.md仕様と46製品で動かす移植性の実装手順で解説しています。
実行して確認したDrizzle ORMの落とし穴4つ
where無しのupdate・deleteは全行が対象
db.update(users).set({ name: 'X' })をwhere無しで実行すると、0.45.3でも1.0.0-rc.4でもエラーや警告は出ず、全行が更新されました(0.45.3で2行がXに変わることを確認)。SQLと同じ挙動なので、ESLintのeslint-plugin-drizzleにあるenforce-update-with-where・enforce-delete-with-whereルールで機械的に止めるのが確実です。
PostgreSQLのクエリエラーとDrizzleQueryErrorのcause
一意制約違反を起こすと、捕まえた例外はDrizzleQueryErrorで、メッセージはFailed query: insert into "users" ...とSQLとパラメータだけでした。PostgreSQLのエラーコード23505はe.cause.codeにあります。e.codeで重複を判定する既存コードは、0.44系以降ではcauseを見るように直します。
tx.rollback()による例外送出と呼び出し元の処理
db.transaction()の中でtx.rollback()を呼ぶと、ロールバック後にTransactionRollbackErrorが送出されます。意図したロールバックでも呼び出し元でtry/catchしないと、未処理の例外として扱われます。
drizzle-kit 0.31.11の列名変更と非TTY環境の制約
列名nameをfull_nameへ変えて非TTY環境でgenerateすると、0.31.11はInteractive prompts require a TTY terminalで終了しました。drizzle-kitは列の削除と追加を「名前の変更」とみなすか対話で確認するためです。リネームを含む差分はローカルの端末でgenerateし、生成したSQLをコミットしてからCIでmigrateします。1.0.0-rc.4のgenerateには--output json・--hints・--hints-fileがあり、リネームの判断をファイルで渡して非対話で実行できます。
PrismaとDrizzle ORMの比較と選び方
設計の違い(比較表)
| 観点 | Drizzle ORM | Prisma ORM |
|---|---|---|
| スキーマ | TypeScriptで定義 | schema.prisma(専用DSL) |
| 型の生成 | 推論(生成手順なし) | prisma generateが必要 |
| クエリ | SQLに近いビルダー+db.query | オブジェクト形式のAPI |
| 依存 | dependencies 0件 | 生成クライアント+DBアダプタ |
| 現行安定版 | 0.45.3 | @prisma/client 7.10.0 |
| 次期版 | 1.0 RC | Prisma ORM 8 RC |
| 週間DL(9/18〜24) | 約2,167万 | 約1,565万(prisma) |
Prismaは7.0.0(2025年11月19日)でRustエンジンを使わないクライアントが新規プロジェクトの既定になり、生成器prisma-clientはTypeScriptを出力します。Prisma ORM 8もRC段階で、公式のリリース状況ページは一般提供を2026年10月の見込みとしています。両者とも次期版がRCのため、2026年秋の選定では「安定版同士で比べ、移行コストを別に見積もる」のが現実的です。
ダウンロード数はnpmの公式APIで取得した値です。Drizzleの数字には他ツールの依存として入る分も含まれるため、採用企業数の比較には使えません。PrismaのバージョンごとのRustエンジン撤廃やESM化などの変更点はPrismaのバージョン完全ガイド|最新v7の変更点・確認方法とv6からの移行にまとめています。
Drizzleを選ぶ条件・選ばない条件
Drizzleが向くのは、発行されるSQLをレビューで確認したいチーム、Cloudflare Workers・Vercel Edgeなどバンドルサイズが効く環境、既存DBをpullで取り込んで段階的に型を付けたい案件です。tRPCと組み合わせてDBからUIまで型をつなぐ構成は、T3 Stackとは?構成技術・型安全の仕組み・メリット/デメリットと始め方でも選択肢になっています。
一方、SQLに不慣れなメンバーが多い、専用DSLのスキーマと生成クライアントを中心にした開発フローで揃えたい、という条件ならPrismaを選びます。DBの閲覧・編集画面はDrizzle Studio(drizzle-kit studio)にもあるため、管理画面の有無は決め手になりません。v1の破壊的変更を今後吸収する余力が無いプロジェクトも、RCが外れるまでは0.45系に固定するか、Prismaを検討してください。デコレータでエンティティを書くTypeORMとの比較はTypeORMとPrismaを比較|2026年版の違いと選び方(型安全・マイグレーション・パフォーマンス)が参考になります。
よくある質問
Drizzle ORMの読み方と意味は?
「ドリズル」と読みます。drizzleは英語で霧雨を意味します。
Drizzle ORMの最新バージョンは?
2026年9月26日時点で、安定版は0.45.3(2026年9月21日公開)、v1の候補版は1.0.0-rc.4(2026年6月27日公開)です。npm view drizzle-orm dist-tagsで最新のタグを確認できます。
drizzle-kit checkは何を確認するコマンド?
マイグレーション履歴のスナップショット同士に矛盾がないかを検査します。複数人が同時にgenerateして履歴が衝突していないかをCIで確かめる用途に使います。0.31.11では問題が無いとEverything's fineと表示されました。
Drizzle ORMでSQL Serverは使える?
1.0 RCでmssql-coreが追加され、SQL Serverに対応しました。安定版の0.45系には含まれていないため、SQL Serverで使うならRC版を選ぶことになります。
drizzle-zodはv1でも必要?
1.0 RCではdrizzle-orm/zod・drizzle-orm/valibotなどがdrizzle-ormに同梱されています。0.45系では別パッケージのdrizzle-zod(latest 0.8.3)を使います。バリデーションライブラリ間の共通仕様はTypeScriptバリデーション断片化を解消するStandard Schemaの全体像で扱っています。