Prisma スキーマ定義チートシート:model/enum/@id/@unique/@index の最短リファレンス
Prisma を使ったアプリケーション開発では、データベースのテーブル構造を schema.prisma ファイルで定義します。この記事では、Prisma スキーマの中でも特に頻繁に使う model、enum、@id、@unique、@index の 5 つの構文に焦点を絞り、実務ですぐに使えるチートシートとしてまとめました。
初めて Prisma に触れる方でも、この記事を見ればスキーマ定義の基本が理解でき、すぐにコードが書けるようになります。
早見表
model 基本構文
| # | 項目 | 構文 | 説明 |
|---|---|---|---|
| 1 | モデル定義 | model ModelName { } | データベースのテーブルに対応するモデルを定義します |
| 2 | フィールド定義 | fieldName Type | フィールド名と型を指定します |
| 3 | オプショナル | fieldName Type? | NULL を許可するフィールドとして定義されます |
| 4 | 配列 | fieldName Type[] | 1 対多のリレーションで使用します |
| 5 | デフォルト値 | @default(value) | フィールドの初期値を設定できます |
enum 構文
| # | 項目 | 構文 | 説明 |
|---|---|---|---|
| 1 | enum 定義 | enum EnumName { } | 固定値の選択肢を定義します |
| 2 | 値の指定 | VALUE_NAME | 大文字スネークケースで記述するのが慣例です |
| 3 | フィールド利用 | status EnumName | モデル内で enum 型として参照できます |
@id(主キー)
| # | 項目 | 構文 | 説明 |
|---|---|---|---|
| 1 | 単一主キー | @id | 1 つのフィールドを主キーに設定します |
| 2 | 自動生成 ID | @id @default(autoincrement()) | 整数型の自動採番 ID として設定されます |
| 3 | UUID 主キー | @id @default(uuid()) | UUID を主キーとして自動生成します |
| 4 | 複合主キー | @@id([field1, field2]) | 複数フィールドの組み合わせを主キーにします |
@unique(一意制約)
| # | 項目 | 構文 | 説明 |
|---|---|---|---|
| 1 | 単一フィールド | @unique | そのフィールドの値を一意にします |
| 2 | 複合 unique | @@unique([field1, field2]) | 複数フィールドの組み合わせを一意にします |
| 3 | 名前付き制約 | @@unique([fields], name: "constraint_name") | 制約に名前を付けて管理しやすくできます |
@index(インデックス)
| # | 項目 | 構文 | 説明 |
|---|---|---|---|
| 1 | 単一インデックス | @@index([fieldName]) | 検索パフォーマンスを向上させます |
| 2 | 複合インデックス | @@index([field1, field2]) | 複数フィールドでの検索を高速化します |
| 3 | 名前付き | @@index([fields], name: "index_name") | インデックスに名前を付けて識別しやすくします |
| 4 | 並び順指定 | @@index([field(sort: Desc)]) | 降順インデックスを作成できます(DB によります) |
背景
Prisma は TypeScript や JavaScript で利用できる次世代 ORM(Object-Relational Mapping)ツールです。従来の ORM と異なり、スキーマファイル(schema.prisma)を中心にした宣言的なデータモデル定義が特徴で、型安全なデータベースアクセスを実現してくれます。
Prisma を導入することで、以下のようなメリットが得られます。
- 型安全: TypeScript の型推論がデータベースクエリにも効くため、実行時エラーを防げます
- 自動マイグレーション: スキーマ定義から SQL マイグレーションを自動生成できます
- 直感的な API: クエリビルダーが読みやすく、学習コストが低いです
以下の図は、Prisma がアプリケーションとデータベースの間でどのように機能するかを示しています。
mermaidflowchart LR
app["アプリケーション<br/>(TypeScript/JavaScript)"] -->|Prisma Client 呼び出し| client["Prisma Client"]
client -->|SQL 実行| db[("データベース<br/>(MySQL/PostgreSQL等)")]
schema["schema.prisma"] -.->|型生成| client
schema -.->|マイグレーション生成| db
Prisma Client はスキーマファイルから自動生成され、型安全なクエリを提供します。マイグレーションもスキーマから生成されるため、開発者はスキーマファイルだけを管理すればよいのです。
スキーマファイルの役割
schema.prisma ファイルは、以下の 3 つの役割を担っています。
- データソース定義: どのデータベースに接続するか
- ジェネレータ定義: どの言語向けのクライアントを生成するか
- データモデル定義: テーブル構造やリレーションの定義
この記事では、3 つ目の「データモデル定義」で使う構文に特化して解説していきます。
課題
Prisma のスキーマ定義は公式ドキュメントが充実していますが、以下のような課題があります。
- 情報が分散している:
model、enum、各アトリビュート(@id、@uniqueなど)の説明が別々のページに分かれており、必要な情報をすぐに見つけにくいです - サンプルが多すぎる: 公式ドキュメントには多くのユースケースが掲載されていますが、初心者には「最低限これだけ知っていればいい」という情報が欲しいところです
- 比較しづらい: 似た機能(
@idと@@id、@uniqueと@@uniqueなど)の違いが一目で分かりません
以下の図は、Prisma 初学者が抱えがちな課題を整理したものです。
mermaidflowchart TD
start["Prisma スキーマを<br/>書きたい"] --> problem1["情報が分散している"]
start --> problem2["構文の違いが<br/>わかりにくい"]
start --> problem3["最低限必要な知識が<br/>わからない"]
problem1 --> solution["チートシート形式で<br/>まとめて解決"]
problem2 --> solution
problem3 --> solution
これらの課題を解決するために、本記事では 最もよく使う 5 つの構文だけ を厳選し、チートシート形式でまとめました。
解決策
この記事では、Prisma スキーマ定義における model、enum、@id、@unique、@index の 5 つに絞り、以下の方針で解説します。
- 構文と用途を対応させる: 各構文がどんな場面で使われるかを明確にします
- 比較表で違いを示す: 似た機能の違いを表形式で整理します
- すぐ使えるサンプルコード: コピーして使える実例を提供します
以下の図は、この記事で扱う 5 つの構文がスキーマ定義のどこで使われるかを示しています。
mermaidflowchart TD
schema["schema.prisma"] --> model["model ブロック"]
schema --> enum["enum ブロック"]
model --> fields["フィールド定義"]
fields --> id["@id / @@id<br/>(主キー)"]
fields --> unique["@unique / @@unique<br/>(一意制約)"]
fields --> index["@@index<br/>(インデックス)"]
enum --> values["固定値の定義"]
それぞれの構文を順番に見ていきましょう。
具体例
ここからは、5 つの構文を具体的なコード例とともに解説していきます。
model(モデル定義)
model はデータベースのテーブルに対応する構造を定義するブロックです。モデル名は PascalCase(単語の先頭を大文字)で記述し、通常は単数形を使います。
基本構文
prismamodel User {
id Int @id @default(autoincrement())
name String
email String @unique
}
上記のコードは、以下の 3 つのフィールドを持つ User テーブルを定義しています。
id: 整数型の主キーで、自動採番されますname: 文字列型の必須フィールドですemail: 文字列型で、一意制約が付いています
フィールドの型指定
Prisma では、以下のような基本型が使えます。
prismamodel Post {
id Int @id @default(autoincrement())
title String // 文字列
content String? // NULL 許可の文字列
published Boolean @default(false) // 真偽値
views Int @default(0) // 整数
rating Float? // 浮動小数点(NULL 許可)
createdAt DateTime @default(now()) // 日時
}
各型の意味は以下の通りです。
String: 文字列型(VARCHAR や TEXT に対応)Int: 整数型(INTEGER に対応)Boolean: 真偽値(BOOLEAN に対応)Float: 浮動小数点数(FLOAT や DOUBLE に対応)DateTime: 日時型(DATETIME や TIMESTAMP に対応)
オプショナルフィールド
型の後ろに ? を付けると、NULL を許可するフィールドになります。
prismamodel Profile {
id Int @id @default(autoincrement())
bio String? // NULL 許可
avatarUrl String? // NULL 許可
userId Int @unique
}
bio と avatarUrl は入力必須ではなく、データがない場合は NULL が入ります。
リレーションの定義
他のモデルとの関連を定義する場合は、参照先のモデル型を使います。
prismamodel User {
id Int @id @default(autoincrement())
name String
posts Post[] // User は複数の Post を持つ
}
prismamodel Post {
id Int @id @default(autoincrement())
title String
authorId Int
author User @relation(fields: [authorId], references: [id])
}
User は複数の Post を持ち(1 対多)、Post は 1 つの User に紐づきます。@relation で外部キーの関係を明示しています。
enum(列挙型)
enum は、フィールドが取りうる値を固定の選択肢として定義する構文です。ステータスや役割など、限られた値しか取らないフィールドに使います。
基本構文
prismaenum Role {
ADMIN
USER
GUEST
}
prismamodel User {
id Int @id @default(autoincrement())
name String
role Role @default(USER)
}
Role という enum を定義し、User モデルの role フィールドで利用しています。デフォルト値は USER です。
enum の利点
enum を使うことで、以下のメリットが得られます。
- 型安全: コード上で不正な値を指定するとコンパイルエラーになります
- 可読性: 値の意味が明確になります
- DB 制約: データベースレベルで値を制限できます(DB によります)
複数の enum を使う例
prismaenum Status {
DRAFT
PUBLISHED
ARCHIVED
}
prismaenum Priority {
LOW
MEDIUM
HIGH
}
prismamodel Task {
id Int @id @default(autoincrement())
title String
status Status @default(DRAFT)
priority Priority @default(MEDIUM)
}
Task モデルは Status と Priority の 2 つの enum を使い、タスクの状態と優先度を管理しています。
@id / @@id(主キー)
主キーは、テーブル内の各レコードを一意に識別するフィールドです。Prisma では @id(単一フィールド)と @@id(複合フィールド)の 2 種類があります。
@id(単一フィールドの主キー)
1 つのフィールドを主キーにする場合は @id を使います。
prismamodel User {
id Int @id @default(autoincrement())
name String
}
id フィールドが主キーとなり、自動採番されます。
UUID を主キーにする
整数の代わりに UUID を主キーにすることもできます。
prismamodel User {
id String @id @default(uuid())
name String
}
uuid() 関数で自動的に UUID が生成されます。分散システムや外部公開 API では、連番 ID よりも UUID が好まれることが多いです。
@@id(複合主キー)
複数のフィールドの組み合わせを主キーにする場合は @@id を使います。
prismamodel UserRole {
userId Int
roleId Int
@@id([userId, roleId])
}
userId と roleId の組み合わせが一意になります。中間テーブル(多対多リレーション)でよく使われます。
@id と @@id の使い分け
以下の表で、2 つの構文の違いを整理します。
| # | 項目 | @id | @@id |
|---|---|---|---|
| 1 | 対象 | 単一フィールド | 複数フィールドの組み合わせ |
| 2 | 記述位置 | フィールドの横 | モデルブロック内の最後 |
| 3 | 利用例 | 通常のテーブル | 中間テーブル、複合キーが必要なテーブル |
| 4 | 自動生成 | @default(autoincrement()) や uuid() が使える | 使えない |
@unique / @@unique(一意制約)
一意制約は、フィールドの値が重複しないようにする制約です。主キーではないが、ユニークであるべきフィールド(メールアドレスやユーザー名など)に使います。
@unique(単一フィールドの一意制約)
1 つのフィールドに一意制約を付ける場合は @unique を使います。
prismamodel User {
id Int @id @default(autoincrement())
email String @unique
}
email フィールドは重複が許されず、同じメールアドレスで複数のユーザーを登録できません。
複数フィールドに個別の一意制約
prismamodel User {
id Int @id @default(autoincrement())
email String @unique
username String @unique
}
email と username の両方に一意制約が付き、それぞれが重複しないようになります。
@@unique(複合一意制約)
複数フィールドの組み合わせを一意にする場合は @@unique を使います。
prismamodel Post {
id Int @id @default(autoincrement())
slug String
locale String
@@unique([slug, locale])
}
slug と locale の組み合わせが一意になります。たとえば、同じ slug でも locale が異なれば登録できます。
名前付き一意制約
一意制約に名前を付けることで、エラーメッセージやマイグレーションファイルでの識別が容易になります。
prismamodel Product {
id Int @id @default(autoincrement())
sku String
size String
@@unique([sku, size], name: "product_sku_size_unique")
}
name パラメータで制約名を指定しています。
@unique と @@unique の比較
| # | 項目 | @unique | @@unique |
|---|---|---|---|
| 1 | 対象 | 単一フィールド | 複数フィールドの組み合わせ |
| 2 | 記述位置 | フィールドの横 | モデルブロック内の最後 |
| 3 | 利用例 | email、username など | 複合キーでの一意性 |
| 4 | 名前付け | できない | name パラメータで可能 |
@@index(インデックス)
インデックスは、データベースの検索パフォーマンスを向上させるための仕組みです。頻繁に検索条件として使うフィールドにインデックスを張ることで、クエリが高速化されます。
基本構文
prismamodel Post {
id Int @id @default(autoincrement())
title String
authorId Int
createdAt DateTime @default(now())
@@index([authorId])
}
authorId フィールドにインデックスが作成され、「特定の著者の投稿を検索する」クエリが速くなります。
複合インデックス
複数のフィールドを組み合わせたインデックスも作れます。
prismamodel Post {
id Int @id @default(autoincrement())
authorId Int
status String
createdAt DateTime @default(now())
@@index([authorId, status])
}
「特定の著者かつ特定のステータス」で検索する場合に効果を発揮します。
名前付きインデックス
インデックスに名前を付けると、データベース管理ツールで識別しやすくなります。
prismamodel Post {
id Int @id @default(autoincrement())
authorId Int
createdAt DateTime @default(now())
@@index([authorId], name: "author_id_index")
@@index([createdAt], name: "created_at_index")
}
複数のインデックスを定義する場合、名前を付けることで管理しやすくなります。
並び順指定(データベース依存)
一部のデータベースでは、インデックスの並び順を指定できます。
prismamodel Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
@@index([createdAt(sort: Desc)], name: "recent_posts_index")
}
降順インデックスを作ることで、「最新の投稿から取得する」クエリが最適化されます。ただし、この機能は MySQL や PostgreSQL など、データベースによって対応状況が異なります。
インデックスを使う場面
以下のような場合にインデックスを検討しましょう。
- 頻繁に検索される: WHERE 句でよく使うフィールド
- 外部キー: リレーション元のフィールド
- ソート対象: ORDER BY でよく使うフィールド
- ユニークではないが検索が多い: ステータスやカテゴリなど
インデックスの注意点
インデックスには以下のトレードオフがあります。
- 読み込みは速くなる: SELECT クエリが高速化されます
- 書き込みは遅くなる: INSERT や UPDATE のたびにインデックスも更新されるため、若干遅くなります
- ストレージを消費する: インデックスはディスク容量を使います
必要な場所にだけインデックスを張り、むやみに増やさないことが大切です。
実践的なスキーマ例
ここまでの内容を組み合わせた、実務で使えるスキーマ例を示します。
prisma// ユーザーの役割を定義
enum Role {
ADMIN
EDITOR
VIEWER
}
prisma// 投稿のステータスを定義
enum PostStatus {
DRAFT
PUBLISHED
ARCHIVED
}
prisma// ユーザーモデル
model User {
id String @id @default(uuid())
email String @unique
username String @unique
role Role @default(VIEWER)
createdAt DateTime @default(now())
posts Post[]
@@index([email])
@@index([createdAt])
}
このスキーマでは、以下の要素を使っています。
- UUID 主キー:
@id @default(uuid())で外部に公開しても安全な ID - 一意制約:
emailとusernameに@unique - enum:
Roleでユーザーの役割を管理 - リレーション:
posts Post[]で 1 対多を定義 - インデックス:
emailとcreatedAtで検索を高速化
prisma// 投稿モデル
model Post {
id Int @id @default(autoincrement())
title String
slug String
content String?
status PostStatus @default(DRAFT)
authorId String
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([slug, authorId])
@@index([authorId])
@@index([status])
@@index([createdAt])
}
Post モデルでは、以下の工夫をしています。
- 複合一意制約:
@@unique([slug, authorId])で同じ著者内で slug が重複しないようにする - 複数インデックス:
authorId、status、createdAtで検索を最適化 - 自動更新:
updatedAtフィールドは@updatedAtで自動的に更新日時が記録されます
以下の図は、User と Post のリレーションとインデックスの関係を示しています。
mermaiderDiagram
User ||--o{ Post : "1対多"
User {
String id PK "UUID"
String email UK "一意制約"
String username UK "一意制約"
Role role "enum"
DateTime createdAt "インデックス"
}
Post {
Int id PK "主キー"
String slug "複合一意制約"
String authorId FK "インデックス, 外部キー"
PostStatus status "インデックス, enum"
DateTime createdAt "インデックス"
}
この図から、主キー(PK)、外部キー(FK)、一意制約(UK)、インデックスがどこに設定されているかが一目で分かります。
まとめ
この記事では、Prisma スキーマ定義の中でも特に重要な model、enum、@id、@unique、@index の 5 つの構文に絞って解説しました。
それぞれのポイントを振り返りましょう。
- model: データベースのテーブルに対応し、フィールドとリレーションを定義します
- enum: 固定の選択肢を型安全に扱え、ステータスや役割の管理に便利です
- @id / @@id: 主キーを定義し、単一フィールドか複合フィールドかで使い分けます
- @unique / @@unique: 一意制約を設定し、重複を防ぎます
- @@index: インデックスを張ることで、検索パフォーマンスを向上させます
これらの構文を使いこなせば、実務で必要な Prisma スキーマのほとんどを記述できるようになります。この記事をチートシートとして手元に置き、スキーマ定義の際に参考にしてください。
Prisma のスキーマ定義は、最初は覚えることが多く感じるかもしれませんが、一度パターンを理解すれば直感的に書けるようになります。ぜひ実際にコードを書きながら、体で覚えていってくださいね。
関連リンク
articlePrisma スキーマ定義チートシート:model/enum/@id/@unique/@index の最短リファレンス
articlePrisma Driver Adapters 導入手順:libSQL/Turso・Neon の最短セットアップ
articlePrisma vs Drizzle vs Kysely:DX・型安全性・最適化余地を実測比較
articlePrisma トラブルシュート大全:P1000/P1001/P1008 ほか接続系エラーの即解決ガイド
articlePrisma アーキテクチャ超図解:Engines/Client/Generator の役割を一枚で理解
articlePrisma の公式ドキュメントを使い倒すためのコツ
articleJotai 運用ガイド:命名規約・debugLabel・依存グラフ可視化の標準化
articleZod vs Ajv/Joi/Valibot/Superstruct:DX・速度・サイズを本気でベンチ比較
articleYarn でモノレポ設計:パッケージ分割、共有ライブラリ、リリース戦略
articleJest を可観測化する:JUnit/SARIF/OpenTelemetry で CI ダッシュボードを構築
articleGitHub Copilot 利用可視化ダッシュボード:受容率/却下率/生成差分を KPI 化
articleWeb Components vs Lit:素の実装とフレームワーク補助の DX/サイズ/速度を実測比較
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来