Content Modeling Guide
How collections, blueprints, entries, globals, navigations, forms, templates and assets fit together, with the 14 field types.
Overview
Airogel CMS stores content as structured data rather than free-form pages. You describe the shape of your content once with a blueprint. You group content of the same kind into a collection. Each piece of content is an entry. Site-wide values live in globals, menus in navigations, and visitor submissions arrive through forms. Templates turn all of this into HTML.
| Building block | What it is | Uses a blueprint? |
|---|---|---|
| Collection | A group of entries with a URL pattern, templates and ordering | Yes, one or more |
| Blueprint | A list of fields (the schema) | — |
| Entry | One item in a collection: title, handle, URL and field values | Yes, one of its collection's |
| Global | A named set of site-wide values, such as site title or social links | Yes, exactly one |
| Navigation | A menu of nested items that link to entries or URLs | Optional, for extra fields on items |
| Form | A visitor-facing form that saves submissions as entries | Uses its collection's blueprint |
| Template | A Liquid layout, page template or partial | No |
| Asset | An uploaded file (image, CSS, JavaScript, PDF…) referenced by path | No |
Blueprints and fields
A blueprint is an ordered list of fields. Each field has:
handle: the key used in templates and the API, unique within the blueprint (for examplehero_image)display: the label shown in the editortype: one of the 14 field types belowoptions: settings for that type, such as the choices of an enumeration or the collection an entity field points to
There are 14 field types:
| Group | Types |
|---|---|
| Text | text, rich_text, raw_html |
| Media | image, gallery, video |
| Relationships | entity, collection, template |
| Values and choices | number, toggle, enumerate |
| Structured data | list, dictionary |
See the Field Types Reference for each type's options and value format.
A blueprint has one owner: a single collection, global or navigation. When you update a blueprint through the API or MCP, the fields list you send replaces the existing list. Fetch the current fields first and include every field you want to keep. Removing a field deletes the values stored in it.
Collections and entries
A collection lists the blueprints its entries may use. Each entry uses one of them, and you can switch an entry to another blueprint later. When you switch, values carry over for fields that have the same handle and type in both blueprints. All other values are dropped.
Every entry has these built-in attributes, in addition to its blueprint fields:
| Attribute | Notes |
|---|---|
title | Required when the entry is created |
handle | URL slug, used by :handle in routing. The API and MCP identify an entry within its collection by its handle. |
published | Default true. Unpublished entries return 404 and are left out of listings, feeds and the sitemap. |
published_at | Used for date routing (:year/:month/:day), feeds and date sorting |
position | Integer sort key, default 0 (see Collections) |
include_in_sitemap | Default true |
Template, layout, routing_override | Optional per-entry overrides of the collection's settings |
content_path | The entry's URL, generated from the routing pattern (read-only) |
On a page, the current entry is available under its collection's handle:
<h1>{{ posts.title }}</h1>
<img src="{{ posts.hero_image }}" alt="">
{{ posts.body }}
Relationships between entries
- Entity fields point at specific entries you choose, such as a post's author or a lesson's course. In templates, the referenced entry behaves like any other entry:
{{ posts.author.title }},{{ posts.author.content_path }}. An entity field can also build nested URLs, for examplecourses/:course/lessons/:handle(see Routing). - Collection fields pull in a filtered, ordered list of entries from another collection, such as "the five latest news posts" or "events tagged with this entry".
- For more complex listings, use the
{% query %}tag in a template. See Liquid Templates.
Globals
A global is a single record of site-wide values with its own blueprint. Every page can use it under the global's handle. New accounts start with a site global:
<title>{{ site.title }}</title>
<meta name="description" content="{{ site.description }}">
Manage globals under Content → Global Data, through the Globals API, or with MCP globals_save.
Navigations
A navigation is a menu of items, and items can nest. An item links either to an entry, in which case its URL follows the entry if the entry moves, or to any URL. A navigation can also have a blueprint, which adds extra fields to its items, such as an icon or a CSS class. In templates:
{% for item in navigation.main_navigation %}
<a href="{{ item.url }}">{{ item.title }}</a>
{% for child in item.children %}…{% endfor %}
{% endfor %}
See the Navigations API.
Forms
A form connects a public form on your site to a collection and one of that collection's blueprints. Each submission is saved as a new entry in that collection, and the blueprint's fields become the form's inputs. Forms can redirect or show a success message, email a notification, and screen spam with a honeypot or an automatic spam check. Render a form in a template with {% form_for form: "contact" %}. See Form For Tag and the Forms API.
Templates and assets
Templates are Liquid files identified by handle. Whether a template acts as a layout, a page template or a partial depends only on how it is used. A collection or entry names its template and layout, and {% render 'handle' %} includes a partial. Assets are uploaded files that templates reference by path, for example {{ 'site.css' | asset_url }}. See Liquid Templates, the Templates API and the Assets API.
Modeling tips
- Create a separate collection for each kind of content that has its own URL shape or listing, such as pages, posts, people or products.
- Use several blueprints within one collection when items share URLs but need different fields.
- Use an entity field when an editor should pick specific items. Use a collection field when the list should update itself.
- Keep handles lowercase with underscores, such as
blog_postsorhero_image. Collection and global handles become Liquid variable names, and{{ blog-posts.title }}does not work. The MCP tools require snake_case handles for new collections, blueprints and globals. - Put values that appear on every page (contact details, social links, footer text) in a global, not in an entry.