Concepts
Attributes
The attribute primitives available in standards and their chainable modifiers.
Each attribute is a typed field on an object. You build it from a primitive function — text, relation, status, and so on — then chain modifiers before passing it to .attribute().
// @noverify
import { object, text, number, select, relation } from "@stndrds/schema";
const DEAL = object({ name: "deals", label: "Deal" })
.labelExpression("{{ name }}")
.attribute(text({ name: "name", label: "Name" }).required())
.attribute(number({ name: "amount", label: "Amount" }))
.attribute(
select({ name: "currency", label: "Currency" })
.options([
{ id: "eur", label: "EUR", value: "EUR", color: "blue" },
{ id: "usd", label: "USD", value: "USD", color: "green" },
])
)
.attribute(relation({ name: "company", label: "Company" }).to("companies").many());Breaking in vNEXT: builders now default to system: true. The .system() modifier has been removed — anything declared in code is automatically system. Call .runtime() only inside tests, seeds, and fixtures to opt out.
Primitives
| Primitive | Use case | Example |
|---|---|---|
text | Single-line strings | text({ name: "name", label: "Name" }).required() |
textarea | Multi-line strings | textarea({ name: "notes", label: "Notes" }) |
richtext | Rich text editor (blocks) | richtext({ name: "body", label: "Body" }) |
number | Numeric values | number({ name: "age", label: "Age" }) |
checkbox | Booleans | checkbox({ name: "active", label: "Active" }) |
date | Dates and timestamps | date({ name: "closedAt", label: "Closed" }) |
phone | E.164 phone numbers | phone({ name: "phone", label: "Phone" }) |
currency | Monetary amounts | currency({ name: "price", label: "Price" }) |
status | Workflow status with groups | status({ name: "stage", label: "Stage" }).options([...]) |
select | One value from a fixed set | select({ name: "kind", label: "Kind" }).options([...]) |
multiselect | Many values from a fixed set | multiselect({ name: "tags", label: "Tags" }).options([...]) |
location | Address / coordinates | location({ name: "address", label: "Address" }) |
file | File attachments | file({ name: "avatar", label: "Avatar" }) |
user | Reference to an actor | user({ name: "ownedBy", label: "Owner" }) |
relation | Foreign-key edge to another object | relation({ name: "company", label: "Company" }).to("companies").many() |
document | Document reference | document({ name: "contract", label: "Contract" }) |
rating | Rating scale | rating({ name: "score", label: "Score" }) |
formula | Computed read-only value | formula({ name: "fullName", label: "Full name" }) |
rollup | Aggregate across a relation | rollup({ name: "totalAmount", label: "Total" }) |
Common chainable modifiers
| Modifier | Effect |
|---|---|
.required() | Marks the attribute as required; validates presence on write |
.optional() | Explicitly marks the attribute as nullable (default for most primitives) |
.runtime() | Opt out of the default system: true (advanced — tests, seeds, fixtures only) |
.icon(name) | Attaches a Lucide icon to the attribute in the UI |
.description(s) | Admin tooltip shown in the attribute editor |
.required() is a schema-level rule enforced by the runtime validator. Your database adapter must separately configure NOT NULL constraints to guarantee hard enforcement at the storage layer.