Data Model

Models

Learn about the concepts for building your data model with Prisma: Models, scalar types, enums, attributes, functions, IDs, default values and more

The data model definition part of the Prisma schema defines your application models (also called Prisma models). Models:

  • Represent the entities of your application domain
  • Map to the tables (relational databases like PostgreSQL) or collections (MongoDB) in your database
  • Form the foundation of the queries available in the generated Prisma Client API
  • When used with TypeScript, Prisma Client provides generated type definitions for your models and any variations of them to make database access entirely type safe.

The following schema describes a blogging platform - the data model definition is highlighted:

datasource db {
  provider = "postgresql"
}

generator client {
  provider = "prisma-client"
  output   = "./generated"
}

model User { 
  id      Int      @id @default(autoincrement()) 
  email   String   @unique
  name    String?
  role    Role     @default(USER) 
  posts   Post[]
  profile Profile?
} 

model Profile { 
  id     Int    @id @default(autoincrement()) 
  bio    String
  user   User   @relation(fields: [userId], references: [id]) 
  userId Int    @unique
} 

model Post { 
  id         Int        @id @default(autoincrement()) 
  createdAt  DateTime   @default(now()) 
  updatedAt  DateTime   @updatedAt
  title      String
  published  Boolean    @default(false) 
  author     User       @relation(fields: [authorId], references: [id]) 
  authorId   Int
  categories Category[]
} 

model Category { 
  id    Int    @id @default(autoincrement()) 
  name  String
  posts Post[]
} 

enum Role { 
  USER 
  ADMIN 
} 

The data model definition is made up of:

The corresponding database looks like this:

Sample database

A model maps to the underlying structures of the data source.
  • In relational databases like PostgreSQL and MySQL, a model maps to a table
  • In MongoDB, a model maps to a collection

Note: In the future there might be connectors for non-relational databases and other data sources. For example, for a REST API it would map to a resource.

The following query creates a User with nested Post and Category records:

const user = await prisma.user.create({
  data: {
    email: "ariadne@prisma.io",
    name: "Ariadne",
    posts: {
      create: [
        {
          title: "My first day at Prisma",
          categories: { create: { name: "Office" } },
        },
        {
          title: "How to connect to a SQLite database",
          categories: { create: [{ name: "Databases" }, { name: "Tutorials" }] },
        },
      ],
    },
  },
});

Your data model reflects your application domain. For example:

  • In an ecommerce application you probably have models like Customer, Order, Item and Invoice.
  • In a social media application you probably have models like User, Post, Photo and Message.

Introspection and migration

There are two ways to define a data model:

  • Write the data model manually and use Prisma Migrate: You can write your data model manually and map it to your database using Prisma Migrate. In this case, the data model is the single source of truth for the models of your application.
  • Generate the data model via introspection: When you have an existing database or prefer migrating your database schema with SQL, you generate the data model by introspecting your database. In this case, the database schema is the single source of truth for the models of your application.

Defining models

Models represent the entities of your application domain. Models are represented by model blocks and define a number of fields. In the example data model above, User, Profile, Post and Category are models.

A blogging platform can be extended with the following models:

model Comment {
  // Fields
}

model Tag {
  // Fields
}

Mapping model names to tables or collections

Prisma model naming conventions (singular form, PascalCase) do not always match table names in the database. A common approach for naming tables/collections in databases is to use plural form and snake_case notation - for example: comments. When you introspect a database with a table named comments, the resulting Prisma model will look like this:

model comments {
  // Fields
}

However, you can still adhere to the naming convention without renaming the underlying comments table in the database by using the @@map attribute:

model Comment {
  // Fields

  @@map("comments")
}

With this model definition, Prisma ORM automatically maps the Comment model to the comments table in the underlying database.

Note: You can also @map a column name or enum value, and @@map an enum name.

@map and @@map allow you to tune the shape of your Prisma Client API by decoupling model and field names from table and column names in the underlying database.

Defining fields

The properties of a model are called fields, which consist of:

A field's type determines its structure, and fits into one of two categories:

  • Scalar types (includes enums) that map to columns (relational databases) or document fields (MongoDB) - for example, String or Int
  • Model types (the field is then called relation field) - for example Post or Comment[]

Scalar fields

The following example extends the Comment and Tag models with several scalar types. Some fields include attributes:

model Comment {
  id      Int    @id @default(autoincrement()) 
  title   String
  content String
}

model Tag {
  name String @id
}

See complete list of scalar field types .

Relation fields

A relation field's type is another model - for example, a post (Post) can have multiple comments (Comment[]):

model Post {
  id       Int       @id @default(autoincrement())
  // Other fields
  comments Comment[] // A post can have many comments
}

model Comment {
  id     Int
  // Other fields
  post   Post @relation(fields: [postId], references: [id]) // A comment can have one post
  postId Int
}

Refer to the relations documentation for more examples and information about relationships between models.

Native types mapping

Native database type attributes describe the underlying database type:

model Post {
  id      Int    @id
  title   String @db.VarChar(200)
  content String
}

Type attributes are:

  • Specific to the underlying provider (e.g., PostgreSQL uses @db.Boolean, MySQL uses @db.TinyInt(1))
  • Written in PascalCase and prefixed by @db
  • Only added during introspection if the native type differs from the default

See native database type attributes for the complete list.

Type modifiers

The type of a field can be modified by appending either of two modifiers:

  • [] Make a field a list
  • ? Make a field optional

Note: You cannot combine type modifiers - optional lists are not supported.

Lists

The following example includes a scalar list and a list of related models:

model Post {
  id       Int       @id @default(autoincrement())
  comments Comment[] // A list of comments
  keywords String[]  // A scalar list
}

Scalar lists are only supported if the database connector supports them natively or at a Prisma ORM level.

Optional and mandatory fields

model Comment {
  id      Int     @id @default(autoincrement())
  title   String       // Required field
  content String?      // Optional field (nullable)
}

Fields without ? are required:

  • Relational databases: Represented via NOT NULL constraints
  • Prisma Client: TypeScript types enforce these fields at compile time

Unsupported types

When you introspect a relational database, unsupported data types are added as Unsupported:

location    Unsupported("POLYGON")?

Fields of type Unsupported don't appear in the generated Prisma Client API, but you can still use raw database access to query them.

The MongoDB connector doesn't support Unsupported types because it supports all scalar types.

Defining attributes

Attributes modify the behavior of fields or model blocks. The following example includes three field attributes (@id , @default , and @unique ) and one block attribute (@@unique):

model User {
  id        Int     @id @default(autoincrement())
  firstName String
  lastName  String
  email     String  @unique
  isAdmin   Boolean @default(false)

  @@unique([firstName, lastName])
}

Some attributes accept arguments - for example, @default accepts true or false:

isAdmin   Boolean @default(false) // short form of @default(value: false)

See complete list of field and block attributes

Defining an ID field

An ID uniquely identifies individual records of a model. A model can only have one ID:

  • In relational databases, the ID can be a single field or based on multiple fields. If a model does not have an @id or an @@id, you must define a mandatory @unique field or @@unique block instead.
  • In MongoDB, an ID must be a single field that defines an @id attribute and a @map("_id") attribute.

Defining IDs in relational databases

In relational databases, an ID can be defined by a single field using the @id attribute, or multiple fields using the @@id attribute.

Single field IDs

In the following example, the User ID is represented by the id integer field:

model User {
  id      Int      @id @default(autoincrement()) 
  email   String   @unique
  name    String?
  role    Role     @default(USER)
  posts   Post[]
  profile Profile?
}
Composite IDs

In the following example, the User ID is represented by a combination of the firstName and lastName fields:

model User {
  firstName String
  lastName  String
  email     String  @unique
  isAdmin   Boolean @default(false)

  @@id([firstName, lastName]) 
}

By default, the name of this field in Prisma Client queries will be firstName_lastName.

You can also provide your own name for the composite ID using the @@id attribute's name field:

model User {
  firstName String
  lastName  String
  email     String  @unique
  isAdmin   Boolean @default(false)

  @@id(name: "fullName", fields: [firstName, lastName]) 
}

The firstName_lastName field will now be named fullName instead.

Refer to the documentation on working with composite IDs to learn how to interact with a composite ID in Prisma Client.

@unique fields as unique identifiers

In the following example, users are uniquely identified by a @unique field. Because the email field functions as a unique identifier for the model (which is required), it must be mandatory:

model User {
  email   String   @unique
  name    String?
  role    Role     @default(USER)
  posts   Post[]
  profile Profile?
}

Constraint names in relational databases
You can optionally define a custom primary key constraint name in the underlying database.

Defining IDs in MongoDB

The MongoDB connector has specific rules for defining an ID field that differs from relational databases. An ID must be defined by a single field using the @id attribute and must include @map("_id").

In the following example, the User ID is represented by the id string field that accepts an auto-generated ObjectId:

model User {
  id      String   @id @default(auto()) @map("_id") @db.ObjectId
  email   String   @unique
  name    String?
  role    Role     @default(USER)
  posts   Post[]
  profile Profile?
}

In the following example, the User ID is represented by the id string field that accepts something other than an ObjectId - for example, a unique username:

model User {
  id      String   @id @map("_id") 
  email   String   @unique
  name    String?
  role    Role     @default(USER)
  posts   Post[]
  profile Profile?
}

MongoDB does not support @@id
MongoDB does not support composite IDs, which means you cannot identify a model with a @@id block.

Defining a default value

You can define default values for scalar fields using the @default attribute:

model Post {
  id         Int        @id @default(autoincrement())
  createdAt  DateTime   @default(now())
  title      String
  published  Boolean    @default(false)
  data       Json       @default("{ \"hello\": \"world\" }")
}

Default values can be:

  • Static values: 5 (Int), "Hello" (String), false (Boolean)
  • Lists: [5, 6, 8] (Int[]), ["Hello", "Goodbye"] (String[])
  • Functions: now(), uuid(), cuid()
  • JSON: Use escaped strings, e.g., @default("{ \"hello\": \"world\" }")

See attribute functions for connector support details.

Defining a unique field

Unique attributes can be defined on a single field using @unique, or on multiple fields using @@unique:

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique      // Single field unique
  name  String?
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  authorId Int

  @@unique([authorId, title]) // Composite unique
}

You can customize the constraint name with the name field: @@unique(name: "authorTitle", [authorId, title])

See working with composite unique identifiers for Prisma Client usage.

Composite type unique constraints (MongoDB)

For MongoDB composite types, you can define unique constraints on nested fields:

type Address {
  street String
  number Int
}

model User {
  id      Int     @id
  email   String
  address Address

  @@unique([email, address.number])
}

Defining an index

Define indexes via @@index:

model Post {
  id      Int     @id @default(autoincrement())
  title   String
  content String?

  @@index([title, content])
}

For MongoDB composite types, use dot notation: @@index([address.city.name])

See custom index names for naming customization.

Defining enums

Enums are defined via the enum block when supported by your database:

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  role  Role    @default(USER)
}

enum Role {
  USER
  ADMIN
}

Defining composite types (MongoDB)

Composite types are only available on MongoDB.

Composite types (embedded documents) allow embedding records inside other records:

model Product {
  id     String  @id @default(auto()) @map("_id") @db.ObjectId
  name   String
  photos Photo[]
}

type Photo {
  height Int
  width  Int
  url    String
}

Supported attributes in composite types: @default, @map, native types (@db.ObjectId)

Not supported: @unique, @id, @relation, @ignore, @updatedAt

Using functions

The Prisma schema supports functions for default values:

model Post {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  uuid      String   @default(uuid())
}

Common functions: now(), uuid(), cuid(), autoincrement(), auto() (MongoDB ObjectId)

Relations

See relations documentation for relationship details.

Models in Prisma Client

Queries (CRUD)

Every model generates CRUD queries in the Prisma Client API:

findMany() | findFirst() | findUnique() | create() | update() | upsert() | delete() | createMany() | updateMany() | deleteMany()

Access via the lowercase model name property: prisma.user.create({ ... })

Type definitions

Prisma Client generates TypeScript types for your models:

export type User = {
  id: number;
  email: string;
  name: string | null;
};

These types ensure type-safe database queries.

Limitations

Every Prisma model must have at least one unique identifier:

  • @id or @@id for primary key
  • @unique or @@unique for unique constraint

On this page