|
| 1 | +--- |
| 2 | +title: Data modeling overview |
| 3 | +description: How to model your application domain in Prisma Next β models, primary keys, scalar fields, and relations. |
| 4 | +url: /orm/next/data-modeling |
| 5 | +metaTitle: Data modeling in Prisma Next |
| 6 | +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. |
| 7 | +badge: early-access |
| 8 | +--- |
| 9 | + |
| 10 | +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. In Prisma Next you author that description as a **schema**, and Prisma Next compiles it into a versioned [contract](/orm/next) that your code, your migrations, and your tooling all read from. |
| 11 | + |
| 12 | +This page introduces the four building blocks you use in every Prisma Next schema: |
| 13 | + |
| 14 | +- [Models](#models) β the entities of your domain |
| 15 | +- [Primary keys](#primary-keys) β how each record is identified |
| 16 | +- [Scalar fields](#scalar-fields) β the individual values a model stores |
| 17 | +- [Relations](#relations) β how models connect to each other |
| 18 | + |
| 19 | +The building blocks below apply to every database. Where they diverge is in how you model relations, which the database-specific guides linked at the end cover in depth. |
| 20 | + |
| 21 | +## Models |
| 22 | + |
| 23 | +A **model** describes one kind of entity in your domain: a user, an order, a blog post. Every model has a unique identity and its own lifecycle, which is what separates it from a plain bag of values. Two posts with the same title are still two different posts, and a user who changes their email address is still the same user. |
| 24 | + |
| 25 | +You declare a model with the `model` keyword and give it a set of fields: |
| 26 | + |
| 27 | +```prisma |
| 28 | +model User { |
| 29 | + id Int @id @default(autoincrement()) |
| 30 | + email String |
| 31 | + name String? |
| 32 | +} |
| 33 | +``` |
| 34 | + |
| 35 | +How a model maps to physical storage, and which models become queryable entry points, depends on the database and is covered in the database-specific guides. |
| 36 | + |
| 37 | +## Primary keys |
| 38 | + |
| 39 | +A **primary key** is the field (or fields) that uniquely identifies each record in a model. Every model needs one. You mark it with the `@id` attribute: |
| 40 | + |
| 41 | +```prisma |
| 42 | +model User { |
| 43 | + id Int @id @default(autoincrement()) |
| 44 | + email String |
| 45 | +} |
| 46 | +``` |
| 47 | + |
| 48 | +The value can be generated by the database or by Prisma Next. Common choices: |
| 49 | + |
| 50 | +- **Auto-incrementing integer** β `Int @id @default(autoincrement())`. Compact and ordered, but sequential and predictable. |
| 51 | +- **UUID** β `String @id @default(uuid())`. Globally unique and safe to generate on the client, at the cost of a wider key. |
| 52 | +- **MongoDB ObjectId** β `ObjectId @id @map("_id")`. The idiomatic MongoDB identifier, embedding a creation timestamp. |
| 53 | + |
| 54 | +A key can also span multiple fields. A **composite primary key** uses the `@@id` block attribute, for when a record is identified by a combination of values rather than a single one: |
| 55 | + |
| 56 | +```prisma |
| 57 | +model UserTag { |
| 58 | + userId Int |
| 59 | + tagId String |
| 60 | +
|
| 61 | + @@id([userId, tagId]) |
| 62 | +} |
| 63 | +``` |
| 64 | + |
| 65 | +### How to pick a primary key |
| 66 | + |
| 67 | +The first decision is **natural vs. surrogate**. A natural key is an attribute that already identifies the record uniquely: a product's SKU, a book's ISBN, a country's ISO code. A surrogate key is a synthetic value with no business meaning: an auto-incrementing integer, a UUID, an ObjectId. |
| 68 | + |
| 69 | +A **natural key** is the right choice when the value is genuinely stable, unique, and externally assigned β a standardized code your application receives rather than invents. A `Country` keyed by its ISO code (`US`, `DE`), a `Currency` keyed by its ISO code (`USD`, `EUR`), or a `UsState` keyed by its two-letter abbreviation are good fits: the code is the identity, it never changes, and using it as the key means other records store a readable value (`US`) directly instead of an opaque number. Reference and lookup tables like these are where natural keys shine. |
| 70 | + |
| 71 | +A **surrogate key** is the better default for most entities you create yourself. The reason is stability: natural keys you'd be tempted to use β a user's email, a product's SKU β do change in practice, and changing a primary key is expensive because everything that already points at the old value has to be updated too. A surrogate never changes, so it stays a dependable identifier for the life of the record. Keep the natural attribute as well and enforce it with `@unique`: a `User` gets a surrogate `id` plus `email String @unique`, a `Product` gets a surrogate `id` plus `sku String @unique`. You get a stable key *and* the uniqueness guarantee. |
| 72 | + |
| 73 | +Once you've chosen a surrogate, pick its type by how the record is created and referenced: |
| 74 | + |
| 75 | +- **Auto-incrementing integer** (`Int @id @default(autoincrement())`) β the smallest and fastest key to index, and naturally ordered by insertion. Good for an internal `Order` or `Invoice` whose id never leaves your system. The trade-offs: the database assigns the value, so you don't know it until after the insert; it's sequential and therefore guessable, which leaks row counts and invites enumeration if you expose it; and separate sources can't generate ids without colliding. |
| 76 | +- **UUID** (`String @id @default(uuid())`) β globally unique and generated in your application before the insert, so you know the id up front and independent sources never collide. A fit for a `User` or `ApiToken` whose id appears in URLs or is created across services, where you don't want to leak counts. The cost is size (a UUID is far wider than an integer) and, for random UUIDs, worse index locality than a sequential key. |
| 77 | +- **MongoDB ObjectId** (`ObjectId @id @map("_id")`) β the idiomatic MongoDB key: generated without coordination, compact, and it embeds its own creation time. The default for any MongoDB model, for example a `Post` document. See the [MongoDB guide](/orm/next/data-modeling/mongodb). |
| 78 | + |
| 79 | +Use a **composite key** when the identity genuinely *is* the combination of two values. The clearest case is a model that links two others: a `UserTag` connecting a user and a tag is identified by the pair `(userId, tagId)`, and a duplicate pair would be meaningless. Avoid composite keys as the identity of ordinary entities, because everything that points at the model then has to carry all of the key's columns. |
| 80 | + |
| 81 | +## Scalar fields |
| 82 | + |
| 83 | +A **scalar field** holds a single value of a primitive type. The common scalar types are: |
| 84 | + |
| 85 | +| Type | Stores | |
| 86 | +| ---------- | ----------------------------------------- | |
| 87 | +| `String` | Text | |
| 88 | +| `Int` | 32-bit integer | |
| 89 | +| `BigInt` | 64-bit integer | |
| 90 | +| `Float` | Floating-point number | |
| 91 | +| `Boolean` | `true` / `false` | |
| 92 | +| `DateTime` | Timestamp | |
| 93 | +| `Json` | Arbitrary JSON value | |
| 94 | +| `ObjectId` | MongoDB document identifier | |
| 95 | + |
| 96 | +This isn't the whole set. Prisma Next's type system is extensible, so more scalar types β a dedicated `Uuid`, or types contributed by extensions β are available beyond the common ones above. |
| 97 | + |
| 98 | +Two modifiers change a field's shape: |
| 99 | + |
| 100 | +- A trailing `?` makes the field **optional** (`name String?`). |
| 101 | +- A trailing `[]` makes it a **list** (`tags String[]`). |
| 102 | + |
| 103 | +### How to pick a data type |
| 104 | + |
| 105 | +Match the type to the **meaning** of the value, not to how it happens to look: |
| 106 | + |
| 107 | +- **An identifier is a `String`, not an `Int`, unless you do arithmetic on it.** Zip codes, phone numbers, and order references look numeric but you never add them, they can have leading zeros, and they aren't ordered numerically. Store them as `String`. |
| 108 | +- **Money is not a `Float`.** Floating-point types can't represent decimal amounts exactly, so sums drift by fractions of a cent. Store currency as an integer number of minor units (cents), or use a dedicated decimal type where one is available. |
| 109 | +- **An instant is a `DateTime`, not a `String`.** A real timestamp type gives you correct comparison, sorting, and range queries; a string gives you none of those and invites format bugs. |
| 110 | +- **A fixed set of values is an enum, not a free-form `String`.** When a field only ever holds one of a known set β a status, a role, a priority β an `enum` documents the allowed values and rejects anything else. (Enum authoring differs slightly by database; see the family guides.) |
| 111 | + |
| 112 | +Size a field for the data it will realistically hold, including future growth. A narrower type (`Int` over `BigInt`) documents intent and costs a little less to store, but the choice is asymmetric: widening a type later β when a counter overflows `Int`, say β is a migration, so when you're unsure, lean toward the type you won't have to change. Mark a field optional (`?`) only when "absent" is a meaningful state distinct from a sensible default; a required field with a default is often the clearer model. |
| 113 | + |
| 114 | +## Relations |
| 115 | + |
| 116 | +A **relation** is a connection between two models. Relations are the backbone of most schemas: a user *has* many orders, an order *belongs to* one user, a post *has* many tags. |
| 117 | + |
| 118 | +Two things describe any relation β its cardinality and which side stores it. |
| 119 | + |
| 120 | +### Cardinality |
| 121 | + |
| 122 | +Cardinality is how many records connect on each side. There are three shapes: |
| 123 | + |
| 124 | +- **One-to-one** β a record on each side links to at most one on the other. A user and their profile; an order and its shipment. |
| 125 | +- **One-to-many** β one record links to many, and each of those links back to a single one. A user and their orders; a post and its comments. |
| 126 | +- **Many-to-many** β records on both sides link to many. Posts and tags; students and courses. |
| 127 | + |
| 128 | +### Ownership |
| 129 | + |
| 130 | +A relation is physically stored by one model holding a link to the other. Which model holds that link, and in what form, is a modeling decision with real consequences β and it's where relational and document databases differ most, so the family guides cover it in depth. |
| 131 | + |
| 132 | +### Declaring a relation |
| 133 | + |
| 134 | +You declare a relation with two kinds of field: |
| 135 | + |
| 136 | +- A **relation field** β a virtual field typed as the related model (for example, `author User`). It has no storage of its own; it tells Prisma Next how to navigate the connection. |
| 137 | +- A field that **stores the connection** β the scalar that actually holds the link (for example, `authorId`). It typically references the other model's primary key, though it can point at any unique field. |
| 138 | + |
| 139 | +The `@relation` attribute ties them together with a **directional** vocabulary: `from` names the local field that holds the link, and `to` names the field it points at. Omit `to` and it defaults to the target model's `@id`. |
| 140 | + |
| 141 | +```prisma |
| 142 | +model Post { |
| 143 | + id Int @id @default(autoincrement()) |
| 144 | + authorId Int |
| 145 | + author User @relation(from: [authorId], to: [id]) |
| 146 | +} |
| 147 | +``` |
| 148 | + |
| 149 | +Which model owns the relation, and how each cardinality is stored, is where the two database families diverge. |
| 150 | + |
| 151 | +## Next steps |
| 152 | + |
| 153 | +The same four building blocks β models, primary keys, scalar fields, and relations β apply to every Prisma Next schema. Where they diverge is in how you model relations, so continue with the guide for your database: |
| 154 | + |
| 155 | +- [Relational data modeling](/orm/next/data-modeling/relational-databases) β one-to-one, one-to-many, many-to-many, and polymorphic relations for PostgreSQL and other SQL targets, including how to pick which side stores the relation. |
| 156 | +- [MongoDB data modeling](/orm/next/data-modeling/mongodb) β the same shapes in the document family, plus the central decision: embed or reference. |
0 commit comments