Appearance
Relationships: One to One
One-to-one is the right fit when exactly one related record should exist on either side of the association. Typical examples are User -> Profile, Order -> Receipt, or Post -> SeoEntry.
hasOne
Use hasOne on the parent-facing side when the related table stores the foreign key.
ts
const User = defineModel('users', {
relations: {
profile: hasOne('Profile', {
foreignKey: 'user_id',
}),
},
})String relation targets use the model name inferred from the related table, including irregular plurals such as people -> Person and children -> Child.
Save or create the related model
ts
await user.profile().create({
locale: 'en',
timezone: 'UTC',
})Query through the relation
ts
await user.load('profile')
const profile = user.getRelation('profile')belongsTo
Use belongsTo on the inverse side when the current model stores the foreign key.
ts
const Profile = defineModel('profiles', {
relations: {
user: belongsTo('User', {
foreignKey: 'user_id',
}),
},
})Access the related model
ts
const profile = await Profile.findOrFail(1)
await profile.load('user')
const user = profile.getRelation('user')Eager load the inverse
ts
const profiles = await Profile.with('user').get()Constrain by the parent
ts
const profiles = await Profile.whereBelongsTo(user, 'user').get()Associate and dissociate
ts
profile.user().associate(user)
await profile.save()
profile.user().dissociate()
await profile.save()One-to-one workflow example
Use a one-to-one relation when the dependent record belongs to one parent and should not be modeled as a collection.
ts
const user = await User.create({
name: 'Amina',
email: '[email protected]',
})
await user.profile().create({
locale: 'en',
timezone: 'UTC',
})Practical notes
- define
hasOneon the parent side - define
belongsToon the record that stores the foreign key - use eager loading when the response needs both sides
- use
associate(...)anddissociate(...)when the inverse side already exists