References
How to model relationships between schemas using the reference field.
The reference field
A reference field stores a UUID pointing to another record. The target schema is configured via targetSchema.
{
"name": "Author",
"slug": "author",
"type": "reference",
"config": {
"targetSchema": "person",
"required": true
}
}
In the GUI, the editor is a searchable dropdown of records from the target schema.
In the API, the stored value is the target record's UUID. Records are returned with the reference stored as that UUID; resolve it with a follow-up request to the target schema if you need the full record.
GET /api/v1/projects/blog/schemas/post/records
Returns a paginated envelope:
{
"data": [
{
"id": "8f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
"data": {
"title": "...",
"author": "b2e1a9c4-3d5f-4f7a-9c2b-1e6d8f0a3b5c"
}
}
],
"total": 1,
"page": 1,
"limit": 50
}
One-to-many
A single reference field gives you a one-to-many relationship. One Post points at one Author; an Author can be pointed at by many Posts.
Many-to-many
For many-to-many, use array of reference:
{
"name": "Tags",
"slug": "tags",
"type": "array",
"config": { "of": { "type": "reference", "config": { "targetSchema": "tag" } } }
}
A Post can have many Tags; a Tag can apply to many Posts.
Bidirectional?
Jaina doesn't enforce inverse relationships. If you want "all Posts by this Author," list the Post records and match on the stored author UUID in your own code:
GET /api/v1/projects/blog/schemas/post/records
Then keep the records whose data.author equals b2e1a9c4-3d5f-4f7a-9c2b-1e6d8f0a3b5c.
Self-references
A schema can reference itself. Useful for trees (categories with parent categories) or sequences (dialogue lines that point to a next line).
{
"name": "Next",
"slug": "next",
"type": "array",
"config": { "of": { "type": "reference", "config": { "targetSchema": "dialogue_line" } } }
}
Cascading delete?
By default, deleting a record leaves dangling references in other records. We don't cascade. The trade-off is intentional: cascading deletes are usually a footgun in content systems where editorial mistakes are common.
If you want to clean up dangling references, list the records, find the ones whose reference UUIDs no longer resolve, and decide what to do programmatically.
Reference vs. embedded (composed) fields
Don't confuse a reference field with a field whose type is set to another schema's slug (e.g. "type": "ability"). They look similar but are different mechanisms:
referencestores a UUID pointing at a separate record. The two records stay independent; you get the UUID back from the API and resolve it yourself.- A schema-slug type (
"type": "<schema-slug>") embeds a full composed object of that schema inline, inside the parent record'sdata. There's no UUID and no separate record — the nested data lives and dies with the parent.
Use reference when the related data is its own record (has its own lifecycle, is listed on its own, is reused by multiple parents). Use a schema-slug type when the nested data only ever makes sense as part of the parent (e.g. an inline stats object on a Monster).