Annotations Guide
Annotations attach metadata to a type, interface, or property.
In practice, most application code uses annotations for three things:
- labels and app-facing metadata
- validation rules
- UI-facing hints that stay close to the model
Start With One Small Example
export interface User {
@meta.label 'Full Name'
@expect.minLength 2
name: string
@meta.label 'Email Address'
email: string.email
@ui.placeholder 'Optional biography'
bio?: string
}That model now carries:
- the TypeScript data shape
- runtime validation rules
- metadata that application code can read later
@meta.*: Labels And App Metadata
Use @meta.* annotations for information your app or tooling may want to read at runtime.
Common examples:
@meta.label— a human-friendly field name@meta.description— longer help text@meta.readonly— read-only fields@meta.sensitive— fields that deserve extra care@meta.example— example data for docs or tooling
export interface Product {
@meta.label 'Product Name'
@meta.description 'Shown in the catalog and checkout'
name: string
}@expect.*: Validation Rules
Use @expect.* when the validation rule is specific to this field and is not already covered by a semantic type.
export interface SignupForm {
@expect.minLength 3
@expect.maxLength 20
username: string
@expect.min 18
age: number.int
}Common validation annotations:
@expect.minLength@expect.maxLength@expect.min@expect.max@expect.int@expect.pattern
If the field already reads naturally as string.email or number.int.positive, prefer the semantic type instead of repeating the same rule with annotations.
@ui.*: UI-Facing Hints
Use @ui.* when the model should carry hints that UI tooling can read later.
export interface ProfileForm {
@meta.label 'Biography'
@ui.placeholder 'Tell us about yourself'
@ui.type 'textarea'
bio?: string
}Common examples:
@ui.placeholder@ui.type@ui.hint@ui.group@ui.order@ui.hidden
These annotations do not generate UI by themselves. They keep the UI-relevant metadata on the model so tools can read it later.
Reuse Annotations Through Named Types
Annotations on a named type are reused when that type is referenced elsewhere.
@meta.label 'Username'
@expect.minLength 3
export type Username = string
export interface User {
username: Username
}That is useful for rules and labels you want to repeat consistently across models.
The One Merge Rule Most Users Need
If a property adds its own annotation, the property-level value wins over the reused one.
@expect.minLength 3
export type Username = string
export interface User {
@expect.minLength 5
username: Username
}In that case, username uses 5, not 3.
For deeper details like append-vs-replace behavior, repeatable annotations, and the full catalog, use the Annotations Reference.
Keep Annotations Practical
- Use semantic types first, annotations second.
- Put labels and descriptions on the model, not in a separate UI config file.
- Keep validation rules close to the field they apply to.
- Use custom annotations only when your app or tooling will actually read them.
- For DB-specific annotations, use the Database Layer docs.
Next Steps
- Annotations Reference — full syntax, inheritance, and built-in annotation catalog
- Validation Guide — how annotations become runtime validation
- Ad-hoc Annotations — annotate existing types without modifying their definition
- Custom Annotations — define your own annotation types
- Metadata — access annotations at runtime