Content Models
Content models define the schema for your content. Every piece of content in Studio follows a model definition that specifies what fields are available, their types, and their constraints.
Four Model Kinds
Studio supports four distinct model kinds, each optimized for a different data pattern.

Collection
A collection holds multiple entries sharing the same schema. Each entry has a unique ID and can be individually created, updated, and deleted.
Use for: Blog posts, team members, products, FAQs, events, testimonials.
{
"id": "blog-posts",
"name": "Blog Posts",
"kind": "collection",
"domain": "blog",
"i18n": true,
"fields": {
"title": { "type": "string", "required": true },
"slug": { "type": "slug", "required": true, "unique": true },
"excerpt": { "type": "text" },
"cover": { "type": "image" },
"author": { "type": "relation", "model": "team-members" },
"published_at": { "type": "date" }
}
}Content format: Object map of entries keyed by entry ID:
{
"a1b2c3d4e5f6": {
"title": "Getting Started",
"slug": "getting-started",
"excerpt": "Learn the basics...",
"published_at": "2026-03-15"
}
}Singleton
A singleton holds exactly one entry per locale. There is no list view — just a single document to edit.
Use for: Site settings, homepage hero, footer configuration, SEO defaults.
{
"id": "site-settings",
"name": "Site Settings",
"kind": "singleton",
"domain": "system",
"i18n": false,
"fields": {
"site_name": { "type": "string", "required": true },
"logo": { "type": "image" },
"tagline": { "type": "text" },
"social_links": {
"type": "array",
"items": {
"type": "object",
"fields": {
"platform": { "type": "string" },
"url": { "type": "url" }
}
}
}
}
}Content format: Flat object of field values (no entry IDs):
{
"site_name": "My Website",
"tagline": "Build something great",
"logo": "media/original/logo.webp"
}Document
A document stores Markdown content with typed frontmatter. The fields define the frontmatter schema, while the body is a full Markdown document.
Use for: Documentation pages, blog articles, long-form content, knowledge base entries.
Documents are identified by a slug rather than a generated ID. The body field holds the Markdown content, and all other fields become frontmatter.
Content format: Frontmatter fields plus a separate body property for the Markdown.
Dictionary
A dictionary stores flat key-value pairs. No field definitions are needed — all content is free-form string keys mapped to string values.
Use for: UI translations, configuration maps, feature flags, i18n string files.
{
"id": "ui-strings",
"name": "UI Strings",
"kind": "dictionary",
"domain": "system",
"i18n": true
}Content format:
{
"nav.home": "Home",
"nav.about": "About Us",
"footer.copyright": "2026 My Company"
}TIP
Dictionaries do not require field definitions. The fields property is omitted entirely. All values must be strings.
Field Types
Studio supports 27 field types across six categories:
Text Fields
| Type | Description | Example |
|---|---|---|
string | Single-line text | Title, name |
text | Multi-line text (textarea) | Description, excerpt |
email | Email address with validation | Contact email |
url | URL with validation | Website link |
slug | URL-safe identifier, auto-generated | URL path segment |
color | Hex color value | Brand color |
phone | Phone number | Contact number |
code | Code snippet (monospaced) | Embed code |
icon | Icon identifier | Menu icon |
Rich Content Fields
| Type | Description | Example |
|---|---|---|
markdown | Markdown content | Article body |
richtext | Rich text (WYSIWYG) | Formatted description |
Number Fields
| Type | Description | Example |
|---|---|---|
number | Generic number | Quantity, sort order |
integer | Whole number | Count, position |
decimal | Decimal number | Price, weight |
percent | Percentage (0-100) | Discount rate |
rating | Rating value (1-5) | Review score |
Boolean Field
| Type | Description | Example |
|---|---|---|
boolean | True/false toggle | Featured, published |
Date Fields
| Type | Description | Example |
|---|---|---|
date | Date only (YYYY-MM-DD) | Published date |
datetime | Date and time (ISO 8601) | Event start time |
Media Fields
| Type | Description | Example |
|---|---|---|
image | Image file reference | Cover photo, avatar |
video | Video file reference | Hero video |
file | Generic file reference | PDF download |
Relational Fields
| Type | Description | Example |
|---|---|---|
relation | Single reference to another entry | Post author |
relations | Array of references | Post categories |
Relation configuration:
{
"author": {
"type": "relation",
"model": "team-members"
},
"categories": {
"type": "relations",
"model": "categories"
}
}Polymorphic relations (multiple target models):
{
"related_items": {
"type": "relations",
"model": ["blog-posts", "pages"]
}
}Structural Fields
| Type | Description | Example |
|---|---|---|
select | Dropdown with predefined options | Status, category |
array | List of items | Tags, features |
object | Nested key-value structure | Address, SEO config |
Select field:
{
"status": {
"type": "select",
"options": ["draft", "published", "archived"]
}
}Array field (simple):
{
"tags": {
"type": "array",
"items": "string"
}
}Array field (objects):
{
"features": {
"type": "array",
"items": {
"type": "object",
"fields": {
"title": { "type": "string" },
"icon": { "type": "icon" }
}
}
}
}Object field (max 2 levels deep):
{
"address": {
"type": "object",
"fields": {
"street": { "type": "string" },
"city": { "type": "string" },
"zip": { "type": "string" }
}
}
}Field Options
Each field can have these configuration options:
| Option | Type | Description |
|---|---|---|
required | boolean | Whether the field must have a value |
unique | boolean | Whether values must be unique across entries |
min | number | Minimum value (numbers) or length (strings) |
max | number | Maximum value (numbers) or length (strings) |
pattern | string | Regex pattern for validation |
default | any | Default value when creating new entries |
description | string | Help text shown in the editor |
options | string[] | Valid options for select fields |
model | string or string[] | Target model(s) for relation fields |
items | string or object | Item schema for array fields |
fields | object | Nested field definitions for object fields |
Domains
Models are organized into domains — logical groups that represent content areas. Common domains include:
blog— Blog posts, authors, categoriesmarketing— Landing pages, testimonials, pricingsystem— Site settings, navigation, UI stringsdocs— Documentation pages, API reference
Domains are purely organizational. They determine the directory structure in your repository (.contentrain/content/{domain}/{modelId}/) but have no functional impact on how content behaves.
Creating Models
Via AI Chat
The easiest way to create a model is through the AI chat:
"Create a collection model called 'Team Members' in the marketing domain with name (required string), role (string), bio (text), avatar (image), and email (email)"
The agent will create the model definition with the correct field schemas and commit it to a review branch.
Via Content Panel
You can also create models from the content panel UI by navigating to the project overview and using the model creation form.
Multi-Locale Support (i18n)
Models can opt into multi-locale support by setting i18n: true. When enabled:
- Separate content files are created per locale (e.g.,
en.json,tr.json) - The content panel shows a locale switcher
- The agent can copy content between locales using the
copy_localetool
Locales are configured at the project level during initialization. A default locale is always required.
TIP
Dictionary models with i18n enabled are ideal for managing UI translations — each locale gets its own set of key-value pairs.
Model Configuration
Model definitions live in .contentrain/models/ as JSON files. Each model file contains:
{
"id": "blog-posts",
"name": "Blog Posts",
"kind": "collection",
"domain": "blog",
"i18n": true,
"description": "Articles published on the company blog",
"fields": {
"title": { "type": "string", "required": true },
"slug": { "type": "slug", "required": true, "unique": true }
}
}| Property | Required | Description |
|---|---|---|
id | Yes | Kebab-case unique identifier |
name | Yes | Human-readable display name |
kind | Yes | One of: collection, singleton, document, dictionary |
domain | Yes | Content domain (directory name) |
i18n | No | Enable multi-locale support (default: false) |
description | No | Description shown in the UI |
fields | Varies | Field definitions (required for all kinds except dictionary) |
Modifying Models
You can update existing models through the AI chat or by editing the model JSON files directly. When using the agent:
"Add a 'featured' boolean field to the Blog Posts model"
The agent will update the model definition and commit the change to a review branch.
WARNING
Removing fields from a model does not automatically remove the corresponding data from existing content entries. The orphaned data will be ignored but remains in the content files until cleaned up.
Next Steps
- Content Editing — Create and manage entries for your models
- AI Chat — Use the agent to build and modify models
- Branches & Review — Review model changes before merging