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.userIdis a requiredRecordfield — every Profile must belong to a User.Profile.useris the forward relation that resolvesuserIdinto a fullUserobject.User.profileis the reverse relation that queries theprofiletable for a record whereuserIdmatches.- Deleting a User automatically cascades to delete any Profile with
userIdpointing 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.userIdisRecord?— a Profile can exist without a User.Profile.userandUser.profileareRelation?— they may resolve tonullwhen included.- Deleting a User clears
userIdon 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 | nullInclude 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 Type | Default Behavior | Configurable |
|---|---|---|
Required (Record) | Cascade — deletes the related Profile | No (always cascade) |
Optional (Record?) | SetNone — removes userId (undefined) | Yes, via @onDelete |
Optional + @nullable (Record? @nullable) | SetNull — sets userId to null | Yes, via @onDelete |
See Delete Behavior for all @onDelete options.
When to Use Required vs Optional
| Scenario | Use |
|---|---|
| Every user must have exactly one profile | Required 1 |
| A profile may or may not be linked to a user | Optional 1 |
| Deleting a user should delete the profile | Required 1 (auto-cascade) |
| Deleting a user should unlink but keep the profile | Optional 1 (default SetNone, or SetNull with @nullable) |
| FK should never change after creation | Add @readonly to the Record field |