- Node.js
- TypeScript
Prismaの使い方|schemaの書き方・migrate・よくあるエラー
Prisma は、TypeScript・Node.js から型付きでデータベースを扱う ORM です。 schema.prisma にテーブルの形(モデル)を書き、prisma migrate dev でテーブルを作り、prisma generate で作られたクライアントから prisma.user.findMany() のように操作します。
npm i -D prisma@7 tsx typescript @types/node
npm i @prisma/client@7 @prisma/adapter-better-sqlite3@7 dotenv
npx prisma init --datasource-provider sqlite --output ../generated/prisma
npx prisma migrate dev --name init # テーブルを作る
npx prisma generate # クライアントを作る(v7 では migrate dev の後に自分で実行)
Prisma ORM 7 から、書き方が大きく変わりました。 検索で出てくる v5・v6 の記事のコードは、そのままでは動かないことがあります。
| 項目 | v6 まで | v7 |
|---|---|---|
| 接続先の URL | schema.prisma の url = env("DATABASE_URL") |
prisma.config.ts の datasource.url |
| ジェネレーター | provider = "prisma-client-js" |
provider = "prisma-client" + output が必須 |
| クライアントの import | from "@prisma/client" |
生成先(from "../generated/prisma/client") |
| DB への接続 | Prisma のエンジンが直接つなぐ | ドライバーアダプターが必須(SQLite は @prisma/adapter-better-sqlite3) |
.env |
自動で読む | 自動では読まない(import "dotenv/config") |
migrate dev のあと |
generate と seed も実行 | どちらも実行しない |
| モジュール | CommonJS | ES Modules("type": "module") |
確認環境:Prisma ORM 7.10.0(prisma・@prisma/client・@prisma/adapter-better-sqlite3)、Node.js 22.22.2、TypeScript 7.0.2、tsx、Ubuntu 24.04 の SQLite で、prisma init・validate・format・generate と、クライアントの CRUD・トランザクション・エラーを実際に動かしました。マイグレーションの SQL は、CLI が使うものと同じ schema engine の Wasm 版(@prisma/schema-engine-wasm 7.10.0)で生成して SQLite に適用しています。migrate dev・migrate deploy などのコマンドの動き(フォルダーの作成・履歴の記録)と v7 の変更点は、Prisma の公式ドキュメント(v7)で確かめました(確認日 2026年10月13日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Prismaの使い方|schemaの書き方・migrate・よくあるエラー」
版について:npm の latest は 8.0 のリリース候補
2026年10月13日時点で、npm i prisma と版を付けずに入れると、8.0.0-rc.22(リリース候補)が入ります。 npm の latest タグが 8.0.0-rc.22、prev タグが 7.10.0(2026年8月25日公開)でした。Prisma のドキュメントでは、Prisma ORM 8 はリリース候補で「API の細部はまだ変わる可能性がある」、一般提供は 2026年10月の予定とされています。この記事は 7 系(7.10.0) で書いています。7 系に固定するには、prisma@7・@prisma/client@7 のように版を付けて入れます。
セットアップ(SQLite)
1. 入れる
mkdir prisma-demo && cd prisma-demo
npm init -y
npm pkg set type=module
npm i -D prisma@7 tsx typescript @types/node
npm i @prisma/client@7 @prisma/adapter-better-sqlite3@7 dotenv
| パッケージ | 役割 |
|---|---|
prisma |
CLI(init・migrate・generate) |
@prisma/client |
クライアントの実行時の部品 |
@prisma/adapter-better-sqlite3 |
SQLite につなぐドライバーアダプター(PostgreSQL は @prisma/adapter-pg) |
dotenv |
.env を読む(v7 は自動で読まない) |
tsx |
TypeScript をそのまま実行する |
tsx については、関連記事「TypeScriptをNode.jsで実行|tsx・ts-node・型ストリップ」で扱っています。ES Modules の設定は「Node.js ESMとCommonJSの違い|import混在の解決表」で扱っています。
2. init
npx prisma init --datasource-provider sqlite --output ../generated/prisma
7.10.0 で実行すると、次のファイルができました。
Initialized Prisma in your project
prisma/
schema.prisma
prisma7.config.ts
.env
.gitignore
.claude/skills/
.windsurf/skills/
.agents/skills/
skills-lock.json
7.10.0 の init は、設定ファイルを prisma7.config.ts という名前で作りました。 ドキュメントの説明は prisma.config.ts で、手元ではどちらの名前でも読み込まれました(両方あると prisma7.config.ts が使われました)。あわせて、AI のコーディングツール向けの説明ファイル(.claude/skills/ など)も作られます。使わない場合は消して問題なく動きました。
できた prisma/schema.prisma と .env です。
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
datasource db {
provider = "sqlite"
}
# .env(init が作るもの。コメントは抜粋)
# Environment variables declared in this file are NOT automatically loaded by Prisma.
DATABASE_URL="file:./dev.db"
.gitignore には .env と /generated/prisma が入ります。生成したクライアントはリポジトリに入れず、npx prisma generate で作り直します。
3. prisma.config.ts
// prisma.config.ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
seed: "tsx prisma/seed.ts",
},
datasource: {
url: env("DATABASE_URL"),
},
});
| 項目 | 意味 |
|---|---|
schema |
schema.prisma の場所(フォルダーを指定すると、中の *.prisma を全部読む) |
migrations.path |
マイグレーションのフォルダー |
migrations.seed |
prisma db seed で実行するコマンド |
datasource.url |
migrate・db push・studio が使う接続先 |
datasource.shadowDatabaseUrl |
migrate dev が使う一時的なデータベース |
import "dotenv/config" を書き忘れると、.env の値が読まれません。 手元で外すと、次のエラーになりました。
Failed to load config file "/path/to/project" as a TypeScript/JavaScript module. Error: PrismaConfigEnvError: Cannot resolve environment variable: DATABASE_URL.
4. クライアントを作る
// src/db.ts
import "dotenv/config";
import { PrismaClient } from "../generated/prisma/client";
import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL ?? "file:./dev.db" });
export const prisma = new PrismaClient({ adapter });
// PostgreSQL の場合(npm i @prisma/adapter-pg)
import { PrismaPg } from "@prisma/adapter-pg";
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
export const prisma = new PrismaClient({ adapter });
// tsconfig.json(v7 のドキュメントの推奨に合わせたもの)
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
"target": "ES2023",
"strict": true,
"skipLibCheck": true,
"noEmit": true,
"types": ["node"]
}
}
この設定で npx tsc -p . がエラーなしで通りました。tsconfig の各項目は、関連記事「tsconfig設定一覧|TypeScript 7対応の推奨値とテンプレート」で扱っています。
schema.prisma の書き方早見表
この記事で使ったスキーマです。ユーザー・プロフィール(1対1)・投稿(1対多)・タグ(多対多)があります。
enum Role {
USER
ADMIN
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
role Role @default(USER)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
posts Post[]
profile Profile?
@@map("users")
}
model Profile {
id Int @id @default(autoincrement())
bio String
userId Int @unique @map("user_id")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("profiles")
}
model Post {
id Int @id @default(autoincrement())
title String
published Boolean @default(false)
authorId Int @map("author_id")
author User @relation(fields: [authorId], references: [id])
tags Tag[]
createdAt DateTime @default(now()) @map("created_at")
@@unique([authorId, title])
@@index([authorId])
@@map("posts")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
posts Post[]
@@map("tags")
}
型
| Prisma の型 | SQLite | PostgreSQL | MySQL |
|---|---|---|---|
String |
TEXT | text | varchar(191) |
Int |
INTEGER | integer | int |
BigInt |
BIGINT | bigint | bigint |
Float |
REAL | double precision | double |
Decimal |
DECIMAL | decimal(65,30) | decimal(65,30) |
Boolean |
BOOLEAN | boolean | tinyint(1) |
DateTime |
DATETIME | timestamp(3) | datetime(3) |
Json |
JSONB | jsonb | json |
Bytes |
BLOB | bytea | longblob |
型? |
NULL を許す | NULL を許す | NULL を許す |
型[] |
リレーション(PostgreSQL ではスカラーの配列も) | ― | ― |
SQLite の列は、各型を並べたモデルから生成した SQL で確かめたものです(enum は TEXT になりました)。PostgreSQL・MySQL の列は Prisma のドキュメント(v7 のスキーマリファレンス)の既定の対応です。@db.VarChar(255) のように書くと、DB 側の型を指定できます。
項目(フィールド)に付ける属性
| 属性 | 意味 | 例 |
|---|---|---|
@id |
主キー | id Int @id |
@default(...) |
既定値 | @default(autoincrement())・@default(now())・@default(uuid())・@default(cuid())・@default(false) |
@unique |
重複を許さない | email String @unique |
@updatedAt |
更新するたびに今の日時が入る | updatedAt DateTime @updatedAt |
@map("名前") |
DB の列名を変える | @map("created_at") |
@relation(...) |
外部キーの指定 | @relation(fields: [authorId], references: [id]) |
@db.型 |
DB 固有の型 | @db.VarChar(255)・@db.Text |
@ignore |
クライアントに出さない | ― |
モデルに付ける属性
| 属性 | 意味 | 例 |
|---|---|---|
@@id([a, b]) |
複合主キー | @@id([studentId, courseId]) |
@@unique([a, b]) |
複合の一意制約 | @@unique([authorId, title]) |
@@index([a]) |
インデックス | @@index([authorId]) |
@@map("名前") |
DB のテーブル名を変える | @@map("users") |
@@map・@map を使うと、コードでは createdAt、DB では created_at のように名前を分けられます。 生成された SQL では "created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP になりました。
リレーション
| 関係 | 書き方 | 外部キーを持つ側 |
|---|---|---|
| 1対1 | 親に profile Profile?、子に userId Int @unique + @relation |
子(@unique が要る) |
| 1対多 | 親に posts Post[]、子に authorId Int + @relation |
子 |
| 多対多(暗黙) | 両方に tags Tag[] / posts Post[] |
Prisma が中間テーブル _PostToTag を作る |
| 多対多(明示) | 中間のモデルを自分で書く | 中間のモデル |
| 自己参照 | 同じモデルに @relation("名前") を2つ |
自分 |
暗黙の多対多(Post.tags・Tag.posts)から生成された中間テーブルです。
CREATE TABLE "_PostToTag" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL,
CONSTRAINT "_PostToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "posts" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "_PostToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "tags" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE UNIQUE INDEX "_PostToTag_AB_unique" ON "_PostToTag"("A", "B");
CREATE INDEX "_PostToTag_B_index" ON "_PostToTag"("B");
中間テーブルに「登録日」や「成績」のような列を持たせたいときは、明示の多対多にします。
model Student {
id Int @id @default(autoincrement())
name String
enrollments Enrollment[]
}
model Course {
id Int @id @default(autoincrement())
title String
enrollments Enrollment[]
}
model Enrollment {
studentId Int
courseId Int
enrolledAt DateTime @default(now())
grade String?
student Student @relation(fields: [studentId], references: [id], onDelete: Cascade)
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
@@id([studentId, courseId])
@@index([courseId])
}
// 自己参照(上司と部下)
model Employee {
id Int @id @default(autoincrement())
name String
managerId Int?
manager Employee? @relation("Management", fields: [managerId], references: [id])
reports Employee[] @relation("Management")
}
prisma validate で通り、Enrollment は PRIMARY KEY ("studentId", "courseId") のテーブルになりました。自己参照の外部キーは、managerId が NULL を許すので ON DELETE SET NULL になりました。
onDelete(親を消したときの動き)
| 値 | 動き |
|---|---|
Cascade |
子も消える |
Restrict |
子があると消せない |
NoAction |
Restrict に近い(DB によって違う) |
SetNull |
子の外部キーを NULL にする(NULL を許す列だけ) |
SetDefault |
子の外部キーを既定値にする |
何も書かないと、必須のリレーションは ON DELETE RESTRICT、NULL を許すリレーションは ON DELETE SET NULL になりました(生成された SQL より)。Post.author に onDelete を書かなかったので、投稿のあるユーザーを消すと P2003 のエラーになります(後述)。
反対側のフィールドを書き忘れたとき
error: Error validating field `author` in model `Post`: The relation field `author` on model `Post` is missing an opposite relation field on the model `User`. Either run `prisma format` or add it manually.
npx prisma format を実行すると、足りない反対側(posts Post[])を自動で書き足します。 手元でも、User に posts Post[] が追加されました。
マイグレーション(prisma migrate)
prisma migrate dev は、schema.prisma との差分から SQL を作って prisma/migrations/<日時>_<名前>/migration.sql に保存し、開発用のデータベースに適用します。 適用した履歴は、データベースの _prisma_migrations テーブルに記録されます。
npx prisma migrate dev --name init
npx prisma generate
上のスキーマから作られる最初の SQL です(抜粋)。
-- CreateTable
CREATE TABLE "users" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"email" TEXT NOT NULL,
"name" TEXT,
"role" TEXT NOT NULL DEFAULT 'USER',
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "posts" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"title" TEXT NOT NULL,
"published" BOOLEAN NOT NULL DEFAULT false,
"author_id" INTEGER NOT NULL,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "posts_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "users" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
CREATE INDEX "posts_author_id_idx" ON "posts"("author_id");
CREATE UNIQUE INDEX "posts_author_id_title_key" ON "posts"("author_id", "title");
@updatedAt の列には DB の既定値が付きません。 値は Prisma Client が入れるので、SQL で直接 INSERT すると NOT NULL のエラーになります。
SQLite で列を変えると、テーブルを作り直す
name String? を name String(必須)に変え、age Int? を足したときの SQL です。SQLite は列の変更が苦手なので、新しいテーブルを作ってデータを移し、名前を付け替えます。
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_users" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"email" TEXT NOT NULL,
"name" TEXT NOT NULL,
"role" TEXT NOT NULL DEFAULT 'USER',
"age" INTEGER,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL
);
INSERT INTO "new_users" ("created_at", "email", "id", "name", "role", "updated_at") SELECT "created_at", "email", "id", "name", "role", "updated_at" FROM "users";
DROP TABLE "users";
ALTER TABLE "new_users" RENAME TO "users";
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
name が NULL の行があると、この INSERT は NOT NULL で失敗します。 必須にする前に、NULL の行を埋めておきます。migrate dev は SQL ファイルを作るだけ(--create-only)にもできるので、データを埋める UPDATE を書き足してから適用できます。
開発と本番で使うコマンド
| 場面 | コマンド | すること |
|---|---|---|
| 開発 | prisma migrate dev --name 名前 |
差分の SQL を作って適用。シャドウ DB でずれ(drift)を調べる |
| 開発 | prisma migrate dev --create-only |
SQL を作るだけ(適用しない) |
| 開発 | prisma migrate reset |
DB を消して全部やり直す(v7 では seed は実行しない) |
| 本番・CI | prisma migrate deploy |
未適用の migration.sql を当てるだけ。シャドウ DB もずれの確認も使わない |
| 本番・CI | prisma migrate status |
未適用・失敗したマイグレーションの確認 |
| 失敗したとき | prisma migrate resolve --rolled-back 名前 / --applied 名前 |
履歴の状態を直す |
| どこでも | prisma migrate diff --from-... --to-... --script |
2つの状態の差分 SQL |
| 試作 | prisma db push |
マイグレーションのファイルを作らずに DB を合わせる |
本番では migrate dev を使わず、migrate deploy を使います。 migrate dev は差分によってはデータベースのリセットを求め、データが消えることがあります。ドキュメントでは、migrate deploy はずれの確認もリセットもせず、シャドウ DB も使わないと説明されています。Spring Boot で同じ役割を持つ Flyway は、関連記事「Flywayの使い方|Spring Boot・命名規則・失敗時の直し方」で扱っています。
コマンド一覧
| コマンド | 意味 |
|---|---|
prisma init |
schema.prisma・設定ファイル・.env を作る(--datasource-provider・--output・--url) |
prisma generate |
クライアントを作る(--watch で変更を見て作り直す) |
prisma validate |
schema.prisma の文法を確かめる |
prisma format |
整形し、足りないリレーションを書き足す |
prisma migrate dev / deploy / reset / status / resolve / diff |
マイグレーション |
prisma db push |
スキーマを DB にそのまま反映(ファイルは作らない) |
prisma db pull |
既存の DB から schema.prisma を作る |
prisma db seed |
初期データを入れる(migrations.seed のコマンド) |
prisma db execute --file x.sql |
SQL ファイルを実行(v7 では接続先は設定ファイルから) |
prisma studio |
ブラウザでデータを見る・編集する(既定のポート 5555) |
prisma version / debug |
版・環境の情報 |
v7 では、migrate dev と db push のあとに prisma generate が自動では動きません。 ドキュメントの v7 の CLI リファレンスにそう書かれています(7.10.0 の prisma migrate --help には「trigger generators」という説明が残っていました)。スキーマを変えたら generate まで実行する、と package.json のスクリプトにまとめておくと忘れにくくなります。
{
"scripts": {
"db:migrate": "prisma migrate dev && prisma generate",
"db:deploy": "prisma migrate deploy",
"db:seed": "prisma db seed"
}
}
CRUD の書き方(実行結果つき)
作る(create)
import { prisma } from "./db";
const alice = await prisma.user.create({
data: {
email: "alice@example.com",
name: "Alice",
profile: { create: { bio: "Backend engineer" } },
posts: {
create: [
{ title: "Prisma 入門", published: true,
tags: { connectOrCreate: [{ where: { name: "orm" }, create: { name: "orm" } }] } },
{ title: "下書き" },
],
},
},
include: { profile: true, posts: { include: { tags: true } } },
});
await prisma.user.createMany({
data: [
{ email: "bob@example.com", name: "Bob" },
{ email: "carol@example.com", name: "Carol", role: "ADMIN" },
],
});
create: {
"id": 1,
"email": "alice@example.com",
"name": "Alice",
"role": "USER",
"createdAt": "2026-10-12T17:57:07.132Z",
"updatedAt": "2026-10-12T17:57:07.132Z",
"profile": { "id": 1, "bio": "Backend engineer", "userId": 1 },
"posts": [
{ "id": 1, "title": "Prisma 入門", "published": true, "authorId": 1, ..., "tags": [ { "id": 1, "name": "orm" } ] },
{ "id": 2, "title": "下書き", "published": false, "authorId": 1, ..., "tags": [] }
]
}
1回の create で、関連するプロフィール・投稿・タグまでまとめて作れます。 connectOrCreate は「あればつなぎ、無ければ作る」です。
読む(findMany・findUnique)
const users = await prisma.user.findMany({
where: { email: { endsWith: "@example.com" } },
select: { id: true, name: true, role: true, _count: { select: { posts: true } } },
orderBy: { id: "asc" },
});
const published = await prisma.post.findMany({
where: { published: true, author: { email: "alice@example.com" } },
include: { author: { select: { name: true } }, tags: { select: { name: true } } },
});
const page = await prisma.user.findMany({ skip: 1, take: 2, orderBy: { id: "asc" }, select: { id: true } });
const count = await prisma.user.count({ where: { role: "USER" } });
findMany: [
{ id: 1, name: 'Alice', role: 'USER', _count: { posts: 2 } },
{ id: 2, name: 'Bob', role: 'USER', _count: { posts: 0 } },
{ id: 3, name: 'Carol', role: 'ADMIN', _count: { posts: 0 } }
]
published: [{"id":1,"title":"Prisma 入門","published":true,"authorId":1,"createdAt":"2026-10-12T17:57:07.132Z","author":{"name":"Alice"},"tags":[{"name":"orm"}]}]
page: [ { id: 2 }, { id: 3 } ]
count USER: 2
| 書き方 | SQL で言うと |
|---|---|
findMany({ where }) |
SELECT ... WHERE |
findUnique({ where: { email } }) |
主キー・@unique で1件(無ければ null) |
findFirst({ where, orderBy }) |
条件に合う最初の1件 |
findUniqueOrThrow / findFirstOrThrow |
無ければ P2025 のエラー |
select / include |
取る列を選ぶ / 関連を一緒に取る |
orderBy・skip・take |
ORDER BY・OFFSET・LIMIT |
count・aggregate・groupBy |
COUNT・SUM など・GROUP BY |
{ contains }・{ startsWith }・{ in: [...] }・{ gte } |
LIKE・IN・>= |
{ author: { email: ... } } |
関連先の条件(JOIN) |
更新・upsert・削除
await prisma.user.update({ where: { email: "bob@example.com" }, data: { name: "Bobby" } });
await prisma.post.updateMany({ where: { published: false }, data: { published: true } }); // { count: 1 }
const up = await prisma.user.upsert({
where: { email: "dave@example.com" },
update: { name: "Dave2" },
create: { email: "dave@example.com", name: "Dave" },
}); // 無かったので作られた:4 Dave
await prisma.post.deleteMany({ where: { authorId: alice.id } }); // { count: 3 }
await prisma.user.delete({ where: { id: alice.id } }); // Profile は Cascade で消えた(残り 0)
トランザクションと生の SQL
// まとめて実行(どれかが失敗したら全部取り消し)
const [post, user] = await prisma.$transaction([
prisma.post.create({ data: { title: "transaction", authorId: alice.id } }),
prisma.user.update({ where: { id: alice.id }, data: { name: "Alice2" } }),
]);
// 途中で判断が要るとき(関数の形)
await prisma.$transaction(async (tx) => {
await tx.user.create({ data: { email: "tx@example.com" } });
await tx.user.create({ data: { email: "tx@example.com" } }); // ここで P2002
});
// 生の SQL(テンプレートリテラルの値はパラメーターになる)
const rows = await prisma.$queryRaw<{ n: bigint }[]>`SELECT COUNT(*) AS n FROM users WHERE role = ${"USER"}`;
// [ { n: 2n } ] ← COUNT は bigint で返る
関数の形のトランザクションで2件目が P2002 になると、1件目も取り消され、tx@example.com のユーザーは 0 件でした。トランザクションの考え方は、関連記事「SQLトランザクションとは|COMMIT・ROLLBACKの書き方と実行結果」で扱っています。
よくあるエラーと直し方
v7 に上げたときのエラー
| エラー(手元で出たもの) | 原因 | 直し方 |
|---|---|---|
SyntaxError: The requested module '@prisma/client' does not provide an export named 'PrismaClient' |
prisma-client のジェネレーターなのに @prisma/client から import |
生成先から import(../generated/prisma/client) |
PrismaClientInitializationError: PrismaClient was instantiated without any options. A driver adapter is required to connect to your database. |
アダプターを渡していない | new PrismaClient({ adapter }) |
PrismaConfigEnvError: Cannot resolve environment variable: DATABASE_URL. |
.env を読んでいない |
設定ファイルの先頭に import "dotenv/config" |
| 型がスキーマの変更前のまま・モデルが無い | migrate dev 後に generate していない |
npx prisma generate |
エラーコード一覧
Prisma Client のエラーは、PrismaClientKnownRequestError の code(P から始まる番号)で見分けます。 メッセージはドキュメント(v7 のエラーリファレンス)の文面です。
| コード | メッセージ(ドキュメントより) | よくある原因 |
|---|---|---|
| P1000 | Authentication failed against database server ... | ユーザー名・パスワードの誤り |
| P1001 | Can't reach database server at {host}:{port} |
DB が起動していない・ホスト名・ポート・ファイアウォール |
| P1002 | The database server ... was reached but timed out. | 接続が詰まっている・ネットワーク |
| P1003 | Database {database_name} does not exist ... |
DB 名の誤り・未作成 |
| P1008 | Operations timed out after {time} |
重いクエリ・ロック待ち |
| P1010 | User {database_user} was denied access on the database ... |
権限不足。v7 の pg アダプターでは SSL 証明書の検証でも出る |
| P1012 | {full_error} |
schema.prisma の文法エラー |
| P1013 | The provided database string is invalid. | 接続文字列の書式(記号の URL エンコード漏れなど) |
| P1017 | Server has closed the connection. | DB の再起動・アイドル切断 |
| P2000 | The provided value for the column is too long for the column's type. | @db.VarChar(n) を超える文字列 |
| P2002 | Unique constraint failed on the {constraint} | @unique・@@unique の重複 |
| P2003 | Foreign key constraint failed on the field: {field_name} |
存在しない親を指定・子がある親を削除 |
| P2011 | Null constraint violation on the {constraint} | 必須の列に NULL |
| P2014 | The change you are trying to make would violate the required relation ... | 必須のリレーションを切る操作 |
| P2021 | The table {table} does not exist in the current database. |
マイグレーションを当てていない |
| P2022 | The column {column} does not exist in the current database. |
スキーマと DB のずれ |
| P2024 | Timed out fetching a new connection from the connection pool. | 接続数が足りない・クライアントの作りすぎ |
| P2025 | An operation failed because it depends on one or more records that were required but not found. | update・delete・OrThrow で対象が無い |
| P2028 | Transaction API error: {error} | トランザクションの時間切れ |
| P2034 | Transaction failed due to a write conflict or a deadlock. Please retry your transaction | デッドロック・書き込みの競合 |
| P3005 | The database schema is not empty. ... | 既存の DB に初めて migrate(baseline が要る) |
| P3006 | Migration {migration_name} failed to apply cleanly to the shadow database. |
migration.sql の誤り・シャドウ DB の権限 |
| P3009 | migrate found failed migrations in the target database ... | 前回の失敗が残っている(migrate resolve) |
| P3014 | Prisma Migrate could not create the shadow database. ... | DB ユーザーに CREATE DATABASE の権限が無い |
| P3018 | A migration failed to apply. ... | 適用中の SQL エラー |
| P3019 | The datasource provider {provider} specified in your schema does not match ... |
migration_lock.toml と provider の不一致 |
手元で出したエラーと中身
SQLite で実際に起こしたエラーです。
import { Prisma } from "../generated/prisma/client";
try {
await prisma.user.create({ data: { email: "taken@example.com" } }); // 既にあるメール
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2002") {
console.log(e.meta);
}
}
| 操作 | code | 出たメッセージ(最後の行) |
|---|---|---|
| 既にあるメールで create | P2002 | Unique constraint failed on the fields: (`email`) |
| 無い ID を update | P2025 | ... No record was found for an update. |
| 無い ID を delete | P2025 | ... No record was found for a delete. |
findUniqueOrThrow で無い ID |
P2025 | ... No record was found for a query. |
無い authorId で投稿を作る |
P2003 | Foreign key constraint violated on the foreign key |
| 投稿のあるユーザーを delete(onDelete なし) | P2003 | 同上 |
email に数値を渡す |
ValidationError | Argument `email`: Invalid value provided. Expected String, provided Int. |
必須の email を渡さない |
ValidationError | Argument `email` is missing. |
v7 のアダプター経由では、P2002 の meta に target がありませんでした。 手元の meta はこうなっていて、重複した列名は driverAdapterError.cause.constraint.fields に入っていました。
{"driverAdapterError":{"name":"DriverAdapterError","cause":{"originalCode":"SQLITE_CONSTRAINT_UNIQUE","originalMessage":"UNIQUE constraint failed: users.email","kind":"UniqueConstraintViolation","constraint":{"fields":["email"]},"table":"users"}},"modelName":"User"}
v6 までの e.meta.target で列名を見ているコードは、v7 に上げたら確かめ直します。重複エラーの DB ごとの見え方は、関連記事「MySQL ERROR 1062 Duplicate entryの直し方」「PostgreSQL duplicate keyの直し方|シーケンスのずれ」で扱っています。
| エラーの型 | 出る場面(ドキュメントより) |
|---|---|
PrismaClientKnownRequestError |
コードのあるエラー(P2002 など)。code・meta を持つ |
PrismaClientUnknownRequestError |
コードの無いエラー |
PrismaClientInitializationError |
起動・接続の失敗(認証・接続先・環境変数) |
PrismaClientValidationError |
引数の誤り(必須が無い・型が違う) |
PrismaClientRustPanicError |
エンジンが落ちた(プロセスの再起動が要る) |
よくある質問
Q. migrate dev と db push の違いは?
A. migrate dev は migration.sql を残して履歴を管理し、db push はファイルを作らずに DB をスキーマに合わせます。試作は db push、チームで共有する DB や本番に向けては migrate dev → migrate deploy が向いています。
Q. 既存の DB に Prisma を入れるには?
A. prisma db pull で DB から schema.prisma を作ります。そのあと migrate を使うには、今の状態を「適用済み」として記録する baseline が要ります(P3005 の対処)。
Q. PrismaClient はどこで作ればよいですか?
A. 1つのファイルで1回作り、それを import して使い回します。リクエストのたびに new PrismaClient() すると、接続が増えて P2024 の原因になります。
Q. SQLite 以外の DB の使い方は?
A. provider とアダプター(PostgreSQL は @prisma/adapter-pg、MySQL・MariaDB は @prisma/adapter-mariadb)を変えます。SQLite そのものの使い方は、関連記事「SQLiteの使い方|コマンド早見表とPython連携を実行例で解説」で扱っています。
まとめ
npm i prismaは今は 8.0 のリリース候補が入る。7 系はprisma@7と版を付ける- v7 は
prisma.config.tsに接続先、prisma-client+output、アダプター必須、.envは dotenv で読む - 7.10.0 の init は
prisma7.config.tsを作った(prisma.config.tsでも動く) migrate devのあとにprisma generateを自分で実行する。本番はmigrate deploy- リレーションは子の側に
@relation(fields, references)。多対多に列を持たせたいときは明示の中間モデル - 反対側のフィールドの書き忘れは
prisma formatで足せる - エラーは
PrismaClientKnownRequestErrorのcodeで見分ける。v7 の P2002 はmeta.targetが無かった
参考・出典
確認日はいずれも 2026年10月13日です。
- Prisma Docs「Upgrade to Prisma ORM 7」:https://www.prisma.io/docs/orm/more/upgrade-guides/upgrading-versions/upgrading-to-prisma-7
- Prisma Docs「Prisma CLI reference(v7)」:https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference
- Prisma Docs「Prisma schema reference(v7)」:https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference
- Prisma Docs「Error message reference(v7)」:https://www.prisma.io/docs/orm/v7/reference/error-reference
- Prisma Docs「Overview of Prisma Migrate(v7)」:https://www.prisma.io/docs/orm/v7/prisma-migrate
- Prisma Docs「Release status」:https://www.prisma.io/docs/orm/release-status
- npm「prisma」:https://www.npmjs.com/package/prisma
- npm「@prisma/adapter-better-sqlite3」:https://www.npmjs.com/package/@prisma/adapter-better-sqlite3
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Prismaの使い方|schemaの書き方・migrate・よくあるエラー」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。