Skip to content
22 changes: 22 additions & 0 deletions .claude/skills/docs-writer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,28 @@ Better:
- Use exact product names: Prisma Postgres, Prisma Compute, Prisma Next. Don't shorten "Prisma Postgres" to "the database" or "Prisma Next" to "the ORM" once a page covers more than one product.
- When you tell the reader something is automatic, show the trigger that makes it happen and how to confirm it did. "Compute injects `DATABASE_URL` automatically" needs a follow-up: "Run `prisma compute env` to confirm it's set."

## Teach in plain language

Open every concept with the plain-words version a newcomer can repeat, then a concrete everyday example, and only then the precise terms. Jargon may appear after the reader has the idea, never as the introduction to it.

Weak (jargon-first):

> Data modeling is the step where you describe the shape of your application's data: the entities it works with, the fields each entity carries, and how those entities connect. You author that description as a schema, and it compiles into a versioned contract that your code, migrations, and tooling all read from.

Better (idea first, example second, terms last):

> Data modeling is the process of describing the data your application needs and how that data is connected.
>
> For example, a blog has users, posts, and comments. A user has fields like an email and a name. These models also relate to each other: a user can write many posts, and a post can have many comments.
>
> In Prisma Next, you define this structure in a `contract.prisma` file. This file becomes the shared contract between your application code, database migrations, and developer tools.

The same rule applies inside sections: when a paragraph packs several decisions together, split it into short subsections, one decision each, and show a code block for every option you name. Guidance that lives only in inline code (`Int @id @default(autoincrement())` mid-sentence) belongs in a fenced block with a sentence of its own.

Never lean on internal vocabulary ("runtime family", "lowering", "execution stack") without a one-line plain definition at first use.

For hands-on guides (anything that builds something), follow the house guide style used by /docs/guides/runtimes/bun and the middleware authoring guide: an Introduction stating what the reader builds, Prerequisites, short numbered step headings ("## 1. Create the middleware"), one action per step with the exact file path on every code block, the real expected output after the step that produces it, a likely-failure line where a step commonly breaks, and options or reference material only after the working result.

## Cut the slop

Delete these on sight. They add length, not clarity.
Expand Down
248 changes: 248 additions & 0 deletions apps/docs/content/docs/orm/next/data-modeling/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
---
title: Overview
description: Describe the data your application needs with models, primary keys, scalar fields, and relations.
url: /orm/next/data-modeling
metaTitle: Data modeling in Prisma Next
metaDescription: Learn the building blocks of a Prisma Next data model, models, primary keys, scalar field types, and relations, and how they map to relational and document databases.
badge: early-access
---

Data modeling is the process of describing the data your application needs and how that data is connected.

For example, a blog has users, posts, and comments. A user has fields like an email and a name. A post has fields like a title and content. These models also relate to each other: a user can write many posts, and a post can have many comments.

In Prisma Next, you define this structure in a `contract.prisma` file. This file becomes the shared contract between your application code, your database migrations, and your developer tools.

If you are coming from Prisma 7, `contract.prisma` plays a similar role to the `schema.prisma` file you used before.

This page introduces the four building blocks of every Prisma Next schema:

- [Models](#models): the things your application works with
- [Primary keys](#primary-keys): how each record is identified
- [Scalar fields](#scalar-fields): the values a model stores
- [Relations](#relations): how models connect to each other

These building blocks apply to every database. Where databases differ is in how you model relations, and the [relational](/orm/next/data-modeling/relational-databases) and [MongoDB](/orm/next/data-modeling/mongodb) guides cover that in depth.

## Models

A model describes one kind of record: a user, an order, a blog post. Declare a model with the `model` keyword and give it fields:

```prisma
model User {
id Int @id @default(autoincrement())
email String
name String?
}
```

Every record of a model has its own identity and its own lifecycle. Two posts with the same title are still two different posts, and a user who changes their email address is still the same user.

On a relational database, a model becomes a table. On MongoDB, it becomes a collection.

## Primary keys

A primary key is the field that uniquely identifies each record. Every model needs one. Mark it with `@id`:

```prisma tab="PostgreSQL"
model User {
id Int @id @default(autoincrement())
email String
}
```

```prisma tab="MongoDB"
model User {
id ObjectId @id @map("_id")
email String
@@map("users")
}
```

On MongoDB, the primary key maps to the document's mandatory `_id` field, and `ObjectId` is the idiomatic type for it.

### Natural keys

A natural key is a value that already identifies the record in the real world. Use one when the value is stable, unique, and assigned outside your application: a standardized code you receive rather than invent.

Reference tables are the classic fit. A country is its ISO code, and the code never changes:

```prisma
model Country {
code String @id
name String
}
```

Records that point at `Country` now store a readable value (`US`, `DE`) instead of an opaque number. Currencies (`USD`, `EUR`) and similar lookup tables work the same way.

### Surrogate keys

A surrogate key is a generated value with no business meaning: an auto-incrementing integer, a UUID, an ObjectId. It is the better default for records your application creates.

The reason is stability. Values you might be tempted to use as a key, like an email address or a product SKU, change in practice. Changing a primary key is expensive because every record that points at the old value must be updated too. A surrogate key never changes.

Keep the natural value as a regular field and enforce its uniqueness with `@unique`. You get a stable key and the uniqueness guarantee:

```prisma
model User {
id Int @id @default(autoincrement())
email String @unique
}

model Product {
id Int @id @default(autoincrement())
sku String @unique
}
```

### Which surrogate type to pick

Pick by how the record is created and where its id travels:

```prisma
// Auto-incrementing integer: smallest and fastest to index,
// ordered by insertion. Good for internal records whose id
// never leaves your system.
model Invoice {
id Int @id @default(autoincrement())
}
```

The database assigns the value, so you only know it after the insert. It is also sequential, so it leaks row counts and invites guessing if you expose it in URLs.

```prisma
// UUID: globally unique, generated before the insert.
// Good for ids that appear in URLs or are created across services.
model ApiToken {
id String @id @default(uuid())
}
```

A UUID is wider than an integer and random UUIDs index a little worse, but independent services never collide and nothing is leaked.

```prisma
// ObjectId: the idiomatic MongoDB key. Generated without
// coordination and embeds its own creation time.
model Post {
id ObjectId @id @map("_id")
@@map("posts")
}
```

### Composite keys

A composite key spans several fields, declared with `@@id`. Use one when the identity really is the combination, which usually means a model that links two others:

```prisma
model UserTag {
userId Int
tagId Int

@@id([userId, tagId])
}
```

A duplicate `(userId, tagId)` pair would be meaningless, so the pair is the key. Avoid composite keys on ordinary models: everything that points at the model then has to carry all of the key's fields.

## Scalar fields

A scalar field holds a single value. The common types:

| Type | Stores |
| ---------- | --------------------------- |
| `String` | Text |
| `Int` | 32-bit integer |
| `BigInt` | 64-bit integer |
| `Float` | Floating-point number |
| `Boolean` | `true` / `false` |
| `DateTime` | Timestamp |
| `Json` | Arbitrary JSON value |
| `ObjectId` | MongoDB document identifier |

Prisma Next's type system is extensible, so extensions can add more types, such as vectors or geometry.

Two modifiers change a field's shape:

- A trailing `?` makes the field optional: `name String?`
- A trailing `[]` makes it a list: `tags String[]`

### How to pick a data type

Match the type to what the value means, not to what it looks like.

An identifier is a `String`, even when it looks numeric. You never add zip codes or phone numbers together, they can have leading zeros, and they do not sort numerically:

```prisma
model Address {
id Int @id @default(autoincrement())
zip String
}
```

Money is not a `Float`. Floating-point numbers cannot represent decimal amounts exactly, so sums drift by fractions of a cent. Store an integer number of the smallest unit:

```prisma
model Product {
id Int @id @default(autoincrement())
priceCents Int
}
```

A point in time is a `DateTime`, not a `String`. A real timestamp type gives you correct comparison, sorting, and range queries:

```prisma
model Post {
id Int @id @default(autoincrement())
publishedAt DateTime
}
```

When you are unsure between two sizes, lean toward the wider one (`BigInt` over `Int` for a counter that could grow). Widening a type later is a migration; the wider type today is free.

Mark a field optional (`?`) only when "absent" means something different from a sensible default. A required field with a default is often the clearer model.

## Relations

A relation connects two models: a user has many posts, a post belongs to one user.

Two kinds of field describe a relation:

- A field that stores the connection. This is a real column or document field, like `authorId`, holding the other record's primary key.
- A relation field, typed as the other model, like `author User`. It stores nothing itself; it tells Prisma Next how to navigate the connection in queries.

The `@relation` attribute ties them together: `fields` names the local field that stores the link, and `references` names the field it points at on the other model.

```prisma
model Post {
id Int @id @default(autoincrement())
authorId Int
author User @relation(fields: [authorId], references: [id])
}
```

Relations come in three shapes:

- One-to-one: a user has at most one profile.
- One-to-many: a user has many posts.
- Many-to-many: a post has many tags, and a tag appears on many posts.

How each shape is stored, and which model should hold the connecting field, is where relational and document databases differ. Continue with the guide for your database:

- [Relational data modeling](/orm/next/data-modeling/relational-databases) for PostgreSQL and other SQL databases: foreign keys, junction tables, and which side owns the key.
- [MongoDB data modeling](/orm/next/data-modeling/mongodb): embedding versus referencing, and polymorphic collections.

## Prompt your coding agent

Projects scaffolded with `create-prisma` install Prisma Next skills for your coding agent; the `prisma-next-contract` skill covers schema authoring. Prompts that map to each section:

- "Using the prisma-next-contract skill, add a Product model with a surrogate id and a unique sku field."
- "Add a Country reference table keyed by its ISO code."
- "Review my schema for fields that should be an enum or a DateTime instead of a String."
- "Connect Post to User with a foreign key and a relation field."

## Next steps

- [Model relational data](/orm/next/data-modeling/relational-databases): one-to-one, one-to-many, many-to-many, and polymorphic relations on SQL databases.
- [Model MongoDB data](/orm/next/data-modeling/mongodb): embed or reference, and single-collection polymorphism.
- [Query your models](/orm/next/fundamentals/reading-data) once the schema is in place.
4 changes: 4 additions & 0 deletions apps/docs/content/docs/orm/next/data-modeling/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"title": "Data modeling",
"pages": ["index", "relational-databases", "mongodb"]
}
Loading
Loading