Skip to content

Content Model

You define content as typed documents. A collection holds many of them, a global holds one, and fields make up each document. Relations link documents across collections. All of it lives in content.config.ts, and the runtime enforces what you define.

Collections

A collection is a set of documents that share the same schema. Define one with defineCollection. The key is the identifier used in URLs (/api/:key) and in relations. The labels are human-facing names.

defineCollection({
key: "posts",
labels: { singular: "Post", plural: "Posts" },
fields: [
{ key: "title", type: "text", required: true },
{ key: "slug", type: "slug", required: true },
{ key: "body", type: "markdown" },
],
});

Every collection document gets an auto-generated id and createdAt/updatedAt timestamps. You add the rest. There is no separate slug field config or timestamp toggle: add a slug field or a date field if your content needs one.

A collection can carry an admin block (titleField, defaultSort) used by future admin tooling, and a hooks map for lifecycle behavior. See Configuration for the full options.

Globals

A global is a singleton document. Use it for site-wide settings, navigation, or anything that exists exactly once.

defineGlobal({
key: "siteSettings",
label: "Site Settings",
fields: [{ key: "siteName", type: "text" }],
});

Globals expose GET /api/globals/:key and PUT /api/globals/:key. They support the same field types and hooks as collections.

Fields

Fields are the building blocks of every document. Each field has a key, a type, and type-specific options. The FieldBase properties available on every field:

PropertyTypePurpose
keystringThe field identifier in the document
labelstringHuman-facing name
descriptionstringHelp text for editors
requiredbooleanReject saves when the value is empty
hiddenbooleanHide from editors but keep in schema
searchablebooleanInclude in text search
indexedbooleanCreate a database index
localizedbooleanStore per-locale variants
defaultValueunknownValue used when none is provided
validatefunctionCustom validation
access{ read?, update? }Per-field access control

See Field Types for every built-in type and its options.

Relations

A relation links one document to another. Use the relation field type with to set to the target collection key, and many to control cardinality.

defineCollection({
key: "posts",
fields: [
{ key: "tags", type: "relation", to: "tags", many: true },
],
});

Relations resolve lazily. When querying, pass include to expand related documents in a single request, and depth to control how far expansion goes:

Terminal window
curl "http://localhost:3000/api/posts?include=tags&depth=1"

The response replaces each relation field with the full related document(s) instead of a bare reference.

Groups and arrays

Two structural field types let you nest:

  • group: a fixed set of nested fields, stored as a single object. Use it for composite values like an address or a social link.
  • array: a repeatable nested field. Use it for lists of structured items. The of property takes a full field definition (not just a type string), so each array item can itself be a group.
{ key: "socialLinks", type: "array", of: {
key: "socialLink", type: "group",
fields: [
{ key: "label", type: "text", required: true },
{ key: "url", type: "text", required: true },
],
}
}

Tabs, rows, and collapsibles

Three field types exist for editor layout, not data shape:

  • tabs: split fields across named tabs. Each tab has its own fields array.
  • row: place fields side by side on one row.
  • collapsible: wrap fields in a collapsible panel with a label.

These are structural only. They do not change how data is stored or queried.

What timbl does not model

timbl owns content structure, validation, and persistence. It does not own your frontend, routing, or presentation. A collection defines what a post is, not how it renders. That separation is what makes the same content portable across an Astro site, a Next.js app, and a mobile client. See Architecture for the package boundaries.

See also