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

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Describe the data your application needs with models, primary keys, scalar fields, and relations.

Location: ORM > 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 ORM, you define this structure in your contract, the `contract.prisma` file that replaced `schema.prisma`. It holds your models the way `schema.prisma` did, and Prisma ORM derives both your TypeScript types and your migrations from it.

There is no `datasource` or `generator` block any more, because the connection string has moved to `prisma.config.ts`. [A complete contract](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#a-complete-contract) shows a whole file together with the config file, and if you are [coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7), that page covers the rename and the rest of the differences.

Prisma ORM 8 supports PostgreSQL and MongoDB today, and [Supported databases](https://www.prisma.io/docs/orm/supported-databases) lists the ones that are coming. Whichever you use, a contract is built from the same four building blocks:

* [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

All four blocks apply to both databases. How you model relations is where the two differ, so continue with [relational data modeling](https://www.prisma.io/docs/orm/data-modeling/relational-databases) or [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb).

## 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?
}
```

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. Give every model one and mark it with `@id`, because `update` and `delete` fail at runtime on a model that has neither a primary key nor a unique field:

  

#### 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 is the document's mandatory `_id` field, and it must be an `ObjectId`. `@map("_id")` gives the field that name in the database. The field takes no `@default`, because MongoDB assigns the id itself when you create a document without one. `@@map("users")` names the collection and is optional: without it, the collection is the model name with a lowercase first letter.

### 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, such as a standardized code you receive rather than invent.

Natural keys fit reference tables best, the tables that hold a fixed set of values other records point at. A country, for example, is identified by its ISO code, and that 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 a meaningless number. Currencies (`USD`, `EUR`) and other reference 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, because it is stable. Values you might be tempted to use as a key, like an email address or a product SKU, change in practice, and 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`, so you get a stable key and the uniqueness guarantee at the same time:

```prisma
model User {
  id    Int    @id @default(autoincrement())
  email 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.
// 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 takes more space than an integer, but independent services never produce the same one. `@default(uuid())` generates a random UUID, and `@default(uuid(7))` generates one that sorts by creation time. On MongoDB there is no choice to make, because the key is always the `ObjectId` shown above.

### 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 itself is the key. [Many-to-many](https://www.prisma.io/docs/orm/data-modeling/relational-databases#many-to-many) writes a model like this one out with its relation fields. Avoid composite keys for ordinary models, though, because everything that points at the model then has to store 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                            |
| `Decimal`, or `Numeric(10, 2)` with a precision and scale | Exact decimal, PostgreSQL `numeric`              |
| `Boolean`                                                 | `true` / `false`                                 |
| `DateTime`                                                | Timestamp, PostgreSQL `timestamptz`              |
| `Bytes`                                                   | Binary data, PostgreSQL `bytea`                  |
| `Json`                                                    | Arbitrary JSON value, PostgreSQL's native `json` |
| `Jsonb`                                                   | Arbitrary JSON value, PostgreSQL's `jsonb`       |
| `ObjectId`                                                | MongoDB document identifier                      |

The PostgreSQL names in the table are the column types Prisma ORM creates. `ObjectId` is the only MongoDB-only type.

Three types arrive in your code as something other than a plain JavaScript value. A `Decimal` reaches you as a string, so nothing is rounded through a JavaScript number, and a `Bytes` value reaches you as a `Uint8Array`. A `DateTime` reaches you as a `Temporal.Instant`, the standard JavaScript type for a point in time. `Temporal` is built into Node.js 26.8.2 and later, but Homebrew's build of Node.js 26 leaves it out, so check with `node -p "typeof Temporal"`. If that prints `undefined`, install the `temporal-polyfill` package and add `import "temporal-polyfill/full/global"` to your app's entry file, before any query runs.

`Json` and `Jsonb` are two separate types, and they differ in how you can filter on them. On a `Jsonb` field, `.where()` compares the whole value, so you can ask whether the column equals a given document but not whether a key inside it matches. A `Json` field cannot be compared in `.where()` at all, so use `Jsonb` unless you specifically need PostgreSQL's plain `json` column. When you need a path query into the document, reach for [raw SQL](https://www.prisma.io/docs/orm/reference/raw-queries). [Extensions](https://www.prisma.io/docs/orm/extensions) add more types, such as vectors or geometry.

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

A field can also hold one of a fixed set of values. Declare them in an `enum` block:

```prisma
enum Priority {
  @@type("pg/text@1")
  Low  = "low"
  High = "high"
}
```

`@@type` says how the values are stored, here as PostgreSQL `text`, written as the database type plus a version that is always `@1` today. On MongoDB, write `@@type("mongo/string@1")`. You can also leave `@@type` out, in which case Prisma ORM infers the storage from the members: text for string values and an integer for whole numbers. [Enums](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#enums) has the rest of the syntax.

### 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`, because floating-point numbers cannot represent decimal amounts exactly and sums drift by fractions of a cent. For ordinary money, use `Int` and store the amount in the currency's smallest unit, such as cents, which also gives you a plain JavaScript number to work with. Reserve `Decimal` for values that need more decimal places than the currency has, such as a per-unit rate:

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

A point in time is a `DateTime`, not a `String`, because 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. For a counter that could grow past two billion, that means `BigInt` over `Int`, since changing `Int` to `BigInt` later needs a migration that picking `BigInt` now lets you skip. `BigInt` does cost you something in your code, though: the value reaches you as a JavaScript `bigint`, which `JSON.stringify` refuses to serialize until you call `.toString()` on it.

Mark a field optional (`?`) only when "absent" means something different from a sensible default, such as `publishedAt DateTime?` where no value means unpublished. 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.

A relation uses two kinds of field. The model that holds the link needs both of them, while the model on the other end needs only a relation field:

* The link field stores the other record's primary key, like `authorId`. Prisma ORM 7 called this the relation scalar field. On a relational database it is the foreign key column, and on MongoDB it is the field holding the other document's `_id`.
* The relation field is typed as the other model, like `author User`. It creates no column of its own and only tells Prisma ORM how to follow the connection in a query.

The `@relation` attribute ties them together: `fields` names the link field, and `references` names the field it points at on the other model. On the other model, `posts Post[]` is the other end of the same relation.

```prisma
model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

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

Relations come in three kinds:

* One-to-one: a user has at most one profile. The model that holds the link gets `@unique` on its link field, and the field on `User` is `profile Profile?`, not a list. [One-to-one](https://www.prisma.io/docs/orm/data-modeling/relational-databases#one-to-one) has both models written out.
* One-to-many: a user has many posts, as in the example above.
* Many-to-many: a post has many tags, and a tag appears on many posts. This needs a model for the join table, with one record per connected pair. Prisma ORM 7 let you write a list field on both sides with no such model, but that form is gone and `npx prisma contract emit` rejects it, so write the model out as [many-to-many](https://www.prisma.io/docs/orm/data-modeling/relational-databases#many-to-many) shows.

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

* [Relational data modeling](https://www.prisma.io/docs/orm/data-modeling/relational-databases) for PostgreSQL: foreign keys, the model for the join table, and which side owns the key.
* [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb): embedding versus referencing, and polymorphic collections.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent, instruction files that tell it how Prisma ORM 8 works. In an existing project, run `npx prisma skills sync` to add them, then try prompts that map to each section:

* "Using the prisma-8 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](https://www.prisma.io/docs/orm/data-modeling/relational-databases): one-to-one, one-to-many, many-to-many, and polymorphic relations on PostgreSQL.
* [Model MongoDB data](https://www.prisma.io/docs/orm/data-modeling/mongodb): embed or reference, and polymorphic collections.
* [Generate a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration) to get the models you wrote into the database. The loop is: edit the contract, run `npx prisma contract emit` to check it and regenerate your types (it replaces `prisma generate`), run `npx prisma migration plan` to write the migration files, then run `npx prisma db migrate` to apply them. That page has the flags and explains how the next plan finds its starting point.
* [Query your models](https://www.prisma.io/docs/orm/fundamentals/reading-data) once your contract is in place.

## Related pages

- [`Coming from Prisma ORM 7`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7): What each Prisma ORM 7 schema attribute, command, and query is called in Prisma ORM 8, and what is not available.
- [`Core concepts`](https://www.prisma.io/docs/orm/core-concepts): The ideas every Prisma ORM command and API builds on: contracts, emitting, plans, the database signature, codecs, and the migration graph.
- [`Extensions`](https://www.prisma.io/docs/orm/extensions): Every package that plugs into Prisma ORM: database packages, column types, indexes, query operations, and middleware, by Prisma and the community.
- [`Prisma 7`](https://www.prisma.io/docs/orm/v7): Prisma ORM is a next-generation Node.js and TypeScript ORM that provides type-safe database access, migrations, and a visual data editor.
- [`Prisma ORM`](https://www.prisma.io/docs/orm/v6): Learn about Prisma ORM