Relations
When writing records with create, createMany, update, or updateMany,
relation fields accept several input formats. Datrix normalizes all of them
internally before hitting the database.
Shortcut formats
For most cases you do not need the full RelationInput object — Datrix accepts
shortcuts that are normalized automatically.
ID shortcut
Pass a single number to set a relation to that record.
// Set author to the record with id 5
await datrix.create("post", {
title: "Hello",
author: 5,
})
Internally normalized to { set: [5] }.
Array shortcut
Pass an array of IDs or { id } objects to set multiple relations at once.
await datrix.create("post", {
title: "Hello",
tags: [1, 2, 3],
})
// { id } objects also work
await datrix.create("post", {
title: "Hello",
tags: [{ id: 1 }, { id: 2 }],
})
Both are normalized to { set: [1, 2, 3] }.
null — clear a relation
Pass null to remove a relation. Behavior depends on the relation kind:
// belongsTo — sets the foreign key to null
await datrix.update("post", 1, { author: null })
// hasOne — clears the relation on the target record
await datrix.update("user", 1, { profile: null })
Passing null to a hasMany or manyToMany relation throws an error.
Use { set: [] } instead to clear all connections.
RelationInput object
For full control, pass a RelationInput object with explicit operation keys.
Multiple keys can be combined in a single call.
connect
Link existing records without replacing others.
await datrix.update("post", 1, {
tags: { connect: [4, 5] },
})
For belongsTo / hasOne (singular), only one ID is allowed.
disconnect
Remove a link without deleting the record.
// By ID — hasMany / manyToMany
await datrix.update("post", 1, {
tags: { disconnect: [4] },
})
// disconnect: true — hasOne / belongsTo (clears the relation)
await datrix.update("user", 1, {
profile: { disconnect: true },
})
set
Replace all current connections with the given IDs. Pass an empty array to clear all connections.
// Replace all tags
await datrix.update("post", 1, {
tags: { set: [1, 2, 3] },
})
// Clear all tags
await datrix.update("post", 1, {
tags: { set: [] },
})
delete
Delete the related record entirely.
await datrix.update("user", 1, {
profile: { delete: true },
})
// hasMany / manyToMany — delete by IDs
await datrix.update("post", 1, {
comments: { delete: [10, 11] },
})
create — nested create
Create a new related record in the same operation. Datrix recursively normalizes the nested data and runs it in the correct order.
// Create a post with a new comment in one call
await datrix.create("post", {
title: "Hello",
comments: {
create: { body: "First comment", author: 3 },
},
})
// Array of creates
await datrix.create("post", {
title: "Hello",
tags: {
create: [{ name: "typescript" }, { name: "backend" }],
},
})
Nesting is supported up to 5 levels deep. Circular chains
(e.g. Author → Post → Author) throw an error — use connect to reference
an existing record instead.
update — nested update
Update a related record in the same operation. Requires a where clause to
identify which record to update.
await datrix.update("post", 1, {
author: {
update: {
where: { id: 3 },
data: { name: "Jane" },
},
},
})
// Array of updates
await datrix.update("post", 1, {
comments: {
update: [
{ where: { id: 10 }, data: { body: "Edited" } },
{ where: { id: 11 }, data: { body: "Also edited" } },
],
},
})
Combining operations
Multiple keys can be combined in a single relation field:
await datrix.update("post", 1, {
tags: {
connect: [5],
disconnect: [2],
create: { name: "new-tag" },
},
})
Behavior by relation kind
| Operation | belongsTo | hasOne | hasMany | manyToMany |
|---|---|---|---|---|
| ID shortcut | ✅ single | ✅ single | ✅ array | ✅ array |
null | ✅ clears FK | ✅ clears target | ❌ | ❌ |
connect | ✅ single | ✅ single | ✅ | ✅ |
disconnect | ✅ | ✅ (true only) | ✅ | ✅ |
set | ✅ single | ✅ single | ✅ | ✅ |
delete | ✅ | ✅ | ✅ | ✅ |
create | ✅ single | ✅ single | ✅ | ✅ |
update | ✅ single | ✅ single | ✅ | ✅ |
belongsTo and hasOne are singular — connecting more than one record
at a time throws INVALID_VALUE.