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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?