Cerial
DecoratorsRelation

@key

The @key decorator disambiguates relations when multiple relations exist between the same two models.

Disambiguates relations when multiple relations exist between the same two models, or when a model has self-referential relations. Both the forward and reverse relations must share the same @key value to pair correctly.

Syntax

@key(name)

The name is an arbitrary string identifier. Matching forward and reverse relations must use the same key.

When Is @key Required?

@key is needed in two situations:

  1. Multiple relations between the same two models — Cerial cannot automatically determine which forward relation pairs with which reverse relation.
  2. Self-referential relations with a reverse lookup — A model that relates to itself needs @key to distinguish forward and reverse directions.

If there is only one relation between two models, @key is not needed — Cerial resolves it automatically.

Multiple Relations to the Same Model

When a model has two or more relations pointing to the same target, each pair needs a unique @key:

model Document {
  id Record @id
  title String

  authorId Record
  author Relation @field(authorId) @model(Writer) @key(author)

  reviewerId Record?
  reviewer Relation? @field(reviewerId) @model(Writer) @key(reviewer)
}

model Writer {
  id Record @id
  name String

  authoredDocs Relation[] @model(Document) @key(author)
  reviewedDocs Relation[] @model(Document) @key(reviewer)
}

Without @key, Cerial wouldn't know whether authoredDocs corresponds to the author relation or the reviewer relation.

const writer = await client.db.Writer.findOne({
  where: { id: writerId },
  include: {
    authoredDocs: true,   // Documents where this writer is the author
    reviewedDocs: true,   // Documents where this writer is the reviewer
  },
});

Self-Referential Relations

A model that references itself needs @key to pair the forward and reverse relations:

model Category {
  id Record @id
  name String
  parentId Record?
  parent Relation? @field(parentId) @model(Category) @key(hierarchy)
  children Relation[] @model(Category) @key(hierarchy)
}
// Get a category with its parent and children
const category = await client.db.Category.findOne({
  where: { id: categoryId },
  include: {
    parent: true,
    children: true,
  },
});

Multiple Self-Referential Relations

If a model has multiple self-referential relation pairs, each pair gets its own key:

model Employee {
  id Record @id
  name String

  managerId Record?
  manager Relation? @field(managerId) @model(Employee) @key(management)
  directReports Relation[] @model(Employee) @key(management)

  mentorId Record?
  mentor Relation? @field(mentorId) @model(Employee) @key(mentorship)
  mentees Relation[] @model(Employee) @key(mentorship)
}
const employee = await client.db.Employee.findOne({
  where: { id: empId },
  include: {
    manager: true,
    directReports: true,
    mentor: true,
    mentees: true,
  },
});

Allowed On

ConstructAllowed
Relation fields
Record fields— (validation error)
Object fields
Tuple elements

@key is strictly for Relation fields. Placing it on a Record field produces a validation error.

Restrictions

  • Key values must match — The forward and reverse relations in a pair must use the exact same @key value.
  • Unique per pair — Within the same model, two forward relations to the same target cannot share the same key. Similarly, two reverse relations from the same source cannot share the same key.
  • Only on Relation fields@key cannot be placed on Record fields, object fields, or tuple elements.
  • Compatible with other relation decorators@key works alongside @field, @model, and @onDelete.

On this page