Relations
How to define typed edges between objects using the relation and document primitives.
Relations describe edges between objects. Standards exposes two primitives — relation for entity foreign keys, and document for typed document references.
// @noverify
import { object, relation, text } from "@stndrds/schema";
export const company = object({ name: "company", label: "Company" })
.attribute(text({ name: "name", label: "Name" }).required())
.attribute(
relation({ name: "contacts", label: "Contacts" })
.to("contact")
.many(),
);relation vs document
relation is a foreign-key edge to another object. It models 1:1, 1:N, and N:N links between entities — for example, a contact belonging to a company, or an invoice having multiple line items. Use relation when the target is a structured record in your schema.
document references a typed document — freeform text content stored alongside your records. Use document when the target carries prose content (notes, contracts, reports) rather than structured fields.
Cardinality
Chain .many() or .one() to declare cardinality. Use the plural form of the attribute name with .many(), and the singular form with .one().
// @noverify
relation({ name: "contacts", label: "Contacts" }).to("contact").many()
relation({ name: "company", label: "Company" }).to("company").one()Qualified edges
.qualifyWith() attaches typed properties directly to the edge itself — not to either endpoint. This is useful for data that belongs to the relationship: ownership percentage, role, start date, weight, and so on.
// @noverify
import { relation, number, date, select } from "@stndrds/schema";
import { assetOwnershipQualifiers } from "./asset-ownership-qualifiers";
relation({ name: "financialAssets", label: "Financial assets" })
.to("financial-assets")
.many()
.qualifyWith(...assetOwnershipQualifiers())Where assetOwnershipQualifiers() returns attribute builders for ownershipType, ownershipPercentage, startDate, and endDate. Each qualifier is a standard attribute builder (number, select, date, …) passed as spread arguments.
Edge properties are persisted in the record_reference_edges.properties column. They are not fields on the related record or the document — they live on the join itself.
Edge properties must be declared with .qualifyWith(). Do not add them as attributes on the related object — they would then apply to all instances of that object, not to this specific relationship.