@model
The @model decorator declares which model a relation points to.
Declares which model a relation points to. Used on both PK (forward) and non-PK (reverse) relations to specify the target model.
Syntax
@model(ModelName)The ModelName must be a valid model defined in the schema (same file or cross-file reference).
PK Side (Forward Relations)
On the PK side, @model() is paired with @field() to form a complete forward relation:
model Post {
id Record @id
title String
authorId Record // FK storage field
author Relation @field(authorId) @model(User) // Forward relation
}@model(User)— tells Cerial this relation points to theUsermodel.- Combined with
@field(authorId), it creates a complete forward relation.
Non-PK Side (Reverse Relations)
On the non-PK side, @model() is the only relation decorator needed — no @field:
model User {
id Record @id
name String
posts Relation[] @model(Post) // Reverse relation
}Cerial automatically resolves the reverse relation by finding the matching forward relation on the Post model.
1 Example
model User {
id Record @id
name String
profile Relation? @model(Profile) // Reverse: optional 1:1
}
model Profile {
id Record @id
bio String
userId Record // FK storage
user Relation @field(userId) @model(User) // Forward: required 1:1
}// Include the profile when querying a user
const user = await client.db.User.findOne({
where: { id: userId },
include: { profile: true },
});
// user.profile: Profile | null1 Example
model User {
id Record @id
name String
posts Relation[] @model(Post) // Reverse: array of posts
}
model Post {
id Record @id
title String
authorId Record // FK storage
author Relation @field(authorId) @model(User) // Forward: required
}// Include related posts when querying a user
const user = await client.db.User.findOne({
where: { id: userId },
include: { posts: true },
});
// user.posts: Post[]N Example
In many-to-many relations, both sides use @model() alongside @field():
model Student {
id Record @id
name String
courseIds Record[]
courses Relation[] @field(courseIds) @model(Course)
}
model Course {
id Record @id
title String
studentIds Record[]
students Relation[] @field(studentIds) @model(Student)
}// Both sides reflect the relationship
const student = await client.db.Student.findOne({
where: { id: studentId },
include: { courses: true },
});
// student.courses: Course[]Cardinality Summary
| Schema | Direction | Cardinality |
|---|---|---|
Relation @field(fk) @model(X) | Forward (PK) | One-to-one (required) |
Relation? @field(fk) @model(X) | Forward (PK) | One-to-one (optional) |
Relation? @model(X) | Reverse (non-PK) | One-to-one (optional) |
Relation[] @model(X) | Reverse (non-PK) | One-to-many |
Relation[] @field(fkArr) @model(X) | Forward (PK, N) | Many-to-many |
Allowed On
| Construct | Allowed |
|---|---|
Relation / Relation? / Relation[] fields | ✅ |
Record fields | — (validation error) |
| Object fields | — |
| Tuple elements | — |
@model is strictly for Relation fields. Placing it on a Record field produces a validation error — Record fields store data, while Relation fields define the virtual relationship.
Rules
- Every
Relationwith@field()must also have@model(). - Reverse relations (
Relation[]orRelation?without@field) only need@model(). - If multiple relations exist between the same two models, use
@keyto disambiguate.