Cerial

One-to-One

Single record on each side — required and optional variants with CRUD operations.

A one-to-one relation links a single record in one model to a single record in another. The PK side stores the foreign key, and the non-PK side defines an optional reverse lookup.

Required One-to-One

A required 1

means the FK field is non-optional — the child record must reference a parent.

model User {
  id Record @id
  name String
  profile Relation @model(Profile)
}

model Profile {
  id Record @id
  bio String?
  userId Record
  user Relation @field(userId) @model(User)
}
  • Profile.userId is a required Record field — every Profile must belong to a User.
  • Profile.user is the forward relation that resolves userId into a full User object.
  • User.profile is the reverse relation that queries the profile table for a record where userId matches.
  • Deleting a User automatically cascades to delete any Profile with userId pointing to that User.

Optional One-to-One

An optional 1

allows the child record to exist without referencing a parent.

model User {
  id Record @id
  name String
  profile Relation? @model(Profile)
}

model Profile {
  id Record @id
  bio String?
  userId Record?
  user Relation? @field(userId) @model(User)
}
  • Profile.userId is Record? — a Profile can exist without a User.
  • Profile.user and User.profile are Relation? — they may resolve to null when included.
  • Deleting a User clears userId on the Profile rather than deleting it.

Add @nullable to the FK field (userId Record? @nullable) to distinguish between "no user" (undefined) and "explicitly null" (null). This also changes the default delete behavior from SetNone to SetNull.

Creating Records

Connect to an existing record

Create a Profile linked to an existing User by providing the User's ID:

const profile = await client.db.Profile.create({
  data: {
    bio: 'Hello world',
    user: { connect: userId },
  },
});

Nested create (forward side)

Create a Profile and its User in a single operation from the forward side:

const profile = await client.db.Profile.create({
  data: {
    bio: 'Software engineer',
    user: { create: { name: 'Alice' } },
  },
});

Nested create (reverse side)

Create a User with an inline Profile from the reverse side:

const user = await client.db.User.create({
  data: {
    name: 'Alice',
    profile: { create: { bio: 'Software engineer' } },
  },
});

Connect from the reverse side

Create a User and link an existing Profile:

const user = await client.db.User.create({
  data: {
    name: 'Alice',
    profile: { connect: profileId },
  },
});

Querying

Include the reverse relation

const user = await client.db.User.findOne({
  where: { id: userId },
  include: { profile: true },
});
// Required: user.profile is Profile
// Optional: user.profile is Profile | null

Include the forward relation

const profile = await client.db.Profile.findOne({
  where: { id: profileId },
  include: { user: true },
});
// profile: { id: CerialId, bio?: string, userId: CerialId, user: User }

Include with options

You can pass orderBy, limit, and offset when including relations:

const user = await client.db.User.findOne({
  where: { id: userId },
  include: {
    profile: { limit: 1 },
  },
});

Updating

Reassign via connect

Change which User a Profile belongs to:

await client.db.Profile.updateMany({
  where: { id: profileId },
  data: { user: { connect: newUserId } },
});

Nested create on update (reverse side)

Create a new Profile for an existing User:

await client.db.User.updateMany({
  where: { id: userId },
  data: {
    profile: { create: { bio: 'New profile' } },
  },
});

Disconnect an optional relation

Remove the link between a Profile and its User. This clears the FK field — it does not delete either record:

await client.db.Profile.updateMany({
  where: { id: profileId },
  data: { user: { disconnect: true } },
});

For optional non-nullable FKs (Record?), disconnect sets the field to NONE (absent). For optional nullable FKs (Record? @nullable), disconnect sets the field to null.

Disconnect is only available on optional relations (Relation?). Required relations cannot be disconnected — the FK field must always have a value.

Disconnect from the reverse side

You can also disconnect from the non-PK side:

await client.db.User.updateMany({
  where: { id: userId },
  data: { profile: { disconnect: true } },
});

Delete Behavior

What happens to related records when a parent is deleted depends on the FK configuration:

FK TypeDefault BehaviorConfigurable
Required (Record)Cascade — deletes the related ProfileNo (always cascade)
Optional (Record?)SetNone — removes userId (undefined)Yes, via @onDelete
Optional + @nullable (Record? @nullable)SetNull — sets userId to nullYes, via @onDelete

See Delete Behavior for all @onDelete options.

When to Use Required vs Optional

ScenarioUse
Every user must have exactly one profileRequired 1
A profile may or may not be linked to a userOptional 1
Deleting a user should delete the profileRequired 1
(auto-cascade)
Deleting a user should unlink but keep the profileOptional 1
(default SetNone, or SetNull with @nullable)
FK should never change after creationAdd @readonly to the Record field

On this page