Overview
Define your data models, embedded types, enums, tuples, and literals using Cerial's schema definition language.
Cerial schemas are defined in .cerial files using a concise, Prisma-inspired syntax. Each schema file describes your database structure — models, embedded types, enums, and more — and Cerial uses them to generate a fully type-safe TypeScript client.
Building Blocks
Every .cerial file is made up of five building blocks:
Model
Models map to SurrealDB tables. They have an id field, typed fields with decorators, and can define relations to other models.
model User {
id Record @id
email Email @unique
name String
age Int?
createdAt Date @createdAt
posts Relation[] @model(Post)
}Models support the full range of features: decorators (@default, @unique, @createdAt, @readonly, etc.), relations (Relation fields with @field and @model), arrays, and optional fields. You can also mark a model as abstract — abstract models serve as reusable field templates and don't produce a database table, TypeScript types, or a client accessor.
abstract model Timestamped {
createdAt Date @createdAt
updatedAt Date @updatedAt
}
model Post extends Timestamped {
id Record @id
title String
content String?
}Object
Objects are embedded types stored inline within model fields. They have typed fields with decorators but no id and no relations.
object Address {
street String
city String
state String
zipCode String? @default("00000")
}
model User {
id Record @id
name String
address Address?
}Objects support field-level decorators including @default, @defaultAlways, @createdAt, @updatedAt, @flexible, and @readonly. They can be nested, used in arrays (Address[]), and referenced across files.
Enum
Enums define named sets of string constants. They generate a const object and a TypeScript union type.
enum Role { Admin, Editor, Viewer }
model User {
id Record @id
role Role @default(Viewer)
}Enum values are always strings — for mixed types (numbers, booleans, structured variants), use a literal instead.
Tuple
Tuples are fixed-length typed arrays with named or positional elements. Three variant styles are supported:
Named — All elements have names:
tuple Coordinate {
lat Float,
lng Float,
z Float?
}Index (unnamed) — Positional types only, no names:
tuple Pair {
Int,
Bool
}Mixed — Named and positional elements together:
tuple Entry {
name String,
Int,
Bool
}Tuple elements can be named (for clarity) or anonymous. Input accepts both array and object form; output is always an array. Elements support @nullable, @default, @defaultAlways, @createdAt, and @updatedAt decorators.
Literal
Literals define union types that can combine specific values, broad types, and structured variants.
literal Status {
"active",
"inactive",
"pending"
}
literal MixedId {
String,
Int
}Literals can include string, int, float, and boolean values, broad types (String, Int, Float, Bool, Date), and references to objects, tuples, enums, or other literals.
Syntax Rules
- Field name comes first, in
camelCase— e.g.,firstName,createdAt - Type follows the field name, in
UpperFirst— e.g.,String,Int,Record,Address - Optional fields use
?after the type — e.g.,String? - Array fields use
[]after the type — e.g.,String[],Tag[] - Decorators follow the type, prefixed with
@— e.g.,@unique,@default("pending") - Comments use
#,//, or/* */— see Comments for all three styles - Private fields in abstract models use
!!privateat the end of a field line to prevent override in child types
abstract model Timestamped {
createdAt Date @createdAt
updatedAt Date @updatedAt
}
abstract model BaseModel {
id Record @id
secret String !!private # cannot be overridden by child
}
model User extends BaseModel {
id Record @id
email Email @unique
name String
}Inheritance
All five building blocks support extends for schema-level inheritance. A child type inherits all fields (or values) from its parent:
object BaseAddress {
street String
city String
country String @default("US")
}
# Inherit all fields, then add more
object FullAddress extends BaseAddress {
state String
zipCode String
}You can selectively pick or omit fields:
# Pick only specific fields
object ShortAddress extends BaseAddress[street, city] {
label String
}
# Omit specific fields
object InternationalAddress extends BaseAddress[!country] {
region String
}Models can only extend abstract models. Concrete-extends-concrete and abstract-extends-concrete are not allowed. Objects, enums, tuples, and literals can extend any type of the same kind.
Example Schema
Here's a more comprehensive schema showing multiple building blocks working together:
# Shared types
enum Role { Admin, Editor, Viewer }
object Address {
street String
city String
state String
zipCode String?
}
tuple Color {
r Int,
g Int,
b Int
}
literal Priority {
"low",
"medium",
"high"
}
# Abstract base for timestamps
abstract model Timestamped {
createdAt Date @createdAt
updatedAt Date @updatedAt
}
# User model — extends Timestamped for auto-timestamps
model User extends Timestamped {
id Record @id
email Email @unique
name String
role Role @default(Viewer)
bio String? @nullable # can be absent OR null
address Address?
favoriteColor Color?
tags String[] @set # auto-deduplicated set
}
# Post model with relation to User
model Post extends Timestamped {
id Record @id
title String
content String
priority Priority @default("medium")
authorId Record
author Relation @field(authorId) @model(User)
}What's in This Section
- Field Types — All built-in types — String, Int, Float, Bool, Date, Record, Uuid, Duration, Decimal, and more.
- Arrays — Array syntax, default behavior, the @set decorator, and supported element types.
- Optional Fields — Optional fields, nullable fields, and the NONE vs null distinction.
- Comments — Three comment styles — hash, double-slash, and block comments.
- Cross-File References — Split schemas across files — recursive scanning, forward references, and shared scopes.
Coming soon
Additional schema pages — Decorators, Typed IDs, Inheritance, Enums, Literals, and more — are being added to the documentation.