Models
A model defines the structure and behavior of your content in Foir. Every piece of data — pages, blog posts, bookings, product records, configurations — is stored as a record that belongs to a model.
Overview
A model is a schema definition that controls what data your records can hold and how they behave. Each model has:
- Key — A unique identifier used in APIs and configuration (e.g.,
page,blog-post,booking) - Name — A display name shown in the admin dashboard
- Fields — The schema that defines the shape of each record (see Field Types)
- Config — Capability flags that control versioning, publishing, variants, and more
Model Capabilities
Every model has a config object that enables or disables features:
| Capability | Description | Default |
|---|---|---|
versioning | Track change history; each update creates a new version | Off |
publishing | Draft/publish workflow; records are not live until explicitly published | Off |
variants | Multiple content versions for different audiences (device, segment, market) | Off |
inline | Model can be used as a field type inside other models | Off |
publicApi | Records are accessible via the public API | Off |
customer_scoped | Records are owned by individual customers | Off |
These capabilities are mix-and-match. A model can have versioning without variants, publishing without versioning, or none at all.
Use Case Categories
Simple Data (no capabilities) — For application data that needs direct read/write without overhead. Records are updated in place with no drafts, versions, or publishing step. Examples: form submissions, bookings, app configuration, feature flags, counters.
Published Content (versioning + publishing) — For content that needs a review workflow. Each edit creates a new version, and content stays in draft until explicitly published. Examples: blog posts, announcements, documentation, policies.
Personalized Content (versioning + publishing + variants) — For content that changes based on audience. Variants target different devices, markets, or customer segments, and each variant has its own version history. Examples: landing pages, navigation menus, promotional banners, product descriptions.
Reusable Components (inline mode) — For models used as field types inside other models. When inline is enabled, the model’s key becomes available as a field type. Examples: hero banners, CTAs, testimonials, product cards.
Quick Reference
| Use Case | Versioning | Publishing | Variants |
|---|---|---|---|
| Blog posts | Yes | Yes | No |
| Landing pages | Yes | Yes | Yes |
| Navigation menus | Yes | Yes | Yes |
| Form submissions | No | No | No |
| App configuration | No | No | No |
| Event bookings | No | No | No |
| Hero banners (inline) | No | No | No |
In the Admin
- Go to Settings > Models
- Click Create Model
- Fill in:
- Name: e.g., “Blog Post”
- Key: auto-generated from the name (e.g.,
blog-post), or set manually
- Configure capabilities (versioning, publishing, variants, etc.)
- Add fields to the schema
- Optionally enable Public API access
- Click Save
Model schemas track changes with version history. When you edit a model’s fields, a new schema version is created, and you can restore a previous schema version if needed.
Via the CLI
List all models
foir models listGet a model by key
foir models get blog-postCreate a model
foir models create --data '{
"key": "blog-post",
"name": "Blog Post",
"pluralName": "Blog Posts",
"fields": [
{ "key": "title", "name": "Title", "type": "text", "required": true },
{ "key": "slug", "name": "Slug", "type": "text", "required": true },
{ "key": "body", "name": "Body", "type": "content" }
],
"config": {
"versioning": true,
"publishing": true,
"publicApi": true
}
}'You can also create models from a directory of JSON files, with optional upsert behavior:
foir models create --dir ./models --upsertUpdate a model
foir models update --data '{
"id": "mod_abc123",
"name": "Blog Post",
"fields": [...]
}'Delete a model
foir models delete mod_abc123List schema versions
foir models versions mod_abc123Via the API
List models
query {
models(limit: 50) {
items {
id
key
name
pluralName
description
category
fields
config
}
total
}
}The config field returns the capability flags:
{
"versioning": true,
"publishing": true,
"variants": true,
"inline": false,
"publicApi": true
}Only models with config.publicApi: true are accessible through the public API.
Query parameters
| Parameter | Type | Description |
|---|---|---|
search | String | Search models by name or key |
filters | [FilterInput!] | Filter conditions |
category | String | Filter by category |
limit | Int | Maximum results to return |
offset | Int | Results to skip |
Config System
Models can also be defined in code using defineModel in your foir.config.ts file. This is useful for version-controlling your model schemas alongside your application code.
See Model Configuration for the full reference.
Best Practices
- Choose the minimal set of capabilities each model needs. Simpler models are faster and easier to work with.
- Use clear, descriptive keys. The key is permanent and used throughout your APIs and configuration.
- Enable
publicApionly on models that need external access. Keep internal data models private. - Use the
--upsertflag withfoir models create --dirto safely sync model definitions from your codebase. - Track schema changes with meaningful descriptions so you can review and roll back if needed.