# Overview (/docs/orm/next/data-modeling)

Location: ORM > Next > Overview

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 contract:

* [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 [#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 [#primary-keys]

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

  

#### PostgreSQL

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

#### MongoDB

```prisma
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 [#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 [#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 [#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 [#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 [#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 [#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 [#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 [#prompt-your-coding-agent]

Projects scaffolded with `create-prisma@next` install [Prisma Next skills](/ai/tools/skills#available-skills-for-prisma-next) for your coding agent; the `prisma-next-contract` skill covers contract 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 contract 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 [#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.

## Related pages

- [`Prisma Next API reference`](https://www.prisma.io/docs/orm/next/reference): Reference index for the Prisma Next ORM client, SQL query builder, pipeline builder, raw queries, and runtime APIs.