Blog
Headless CMS Schema Design Checklist for Fast Teams
March 21, 2026
Schema design quality determines how quickly teams can ship content-driven features. Bad models push complexity into every frontend branch; good models make APIs boring and editors confident.
Use this checklist before you lock a new collection or refactor an old one. Where it helps, notes refer to Noma (Noma Core: nomacms/nomacms-core) so your schema matches what the product actually enforces.
1) Field definitions
Intent: Every field has one job, one type, and clear validation—no “misc JSON” for things that should be structured.
- Names are stable API keys —
camelCaseorsnake_caseper team convention; never rename casually (clients cache and query by name). - Types match reality — use
numberfor numbers,enumerationfor fixed vocabularies,richtextvslongtexton purpose (semantics and editors differ). - Required is explicit — in Noma,
requiredon the field plusvalidations.requireddrive server-side rules inContentRequest; don’t rely on UI hints alone. - Character limits — when you need them, charcount validations (
min/max) align editor feedback with API rejection. - Groups and repeatables —
groupfields andrepeatableoptions model lists and blocks without stuffing freeform HTML.
Noma field types to choose deliberately: text, longtext, richtext, slug, email, password, number, enumeration, boolean, color, date, time, media, relation, json, group (see schema in the dashboard and Field types in the app).
Editor vs API surface
hiddenInAPI— field stays in the admin but is omitted fromContentEntryResource(internal notes, migration-only fields).hideInContentList— reduce noise in list tables without hiding from detail or API unless combined withhiddenInAPI.
2) Collections and entry shape
Intent: A collection is a bounded contract—one responsibility per collection unless you have a strong reason.
- Singleton vs repeating —
is_singletonenforces a single entry in the collection when creation rules are satisfied (with locale taken into account when provided—use for site settings, global config). Repeating models use normal collections with many entries. - Slug strategy — one collection often has a
slugfield tied to a source text field viaslug.fieldoptions; decide whether slugs are readonly after publish. - Ordering —
orderon collections and fields controls admin UX; keep field order aligned with how editors think (hero → body → SEO).
3) Relations and references
Intent: Relations are the fastest way to create circular or N+1 API problems if you over-link.
- Model only what you query — if the UI never needs “related author bios,” don’t add the relation until you need it.
- Relation options —
relation.collectionandrelation.type(cardinality / behavior) must match how the frontend resolves nested content (single vs multiple). - Avoid deep cycles — A → B → A makes caching and “what to include in one request” painful; prefer shallow graphs or denormalized snapshots for lists.
- JSON fields —
jsonis an escape hatch; use it for extension data, not for core layout that the site depends on.
4) Localization model
Intent: Locale rules are decided in the schema phase, not discovered at launch.
- Project locales —
default_localeandlocales[]define what editors can create; entries storelocaleper row. - Translation linkage — variants of the same logical item share
translation_group_id; see How to Model Multilingual Content Without Duplicate Entries. - Slug per locale — slug fields are typically per entry; localized slugs need redirect and SEO planning.
- Singleton + locale — one global settings row per locale is a common pattern; confirm whether the API should always pass
localeor rely ondefault_localefor singleton reads.
5) Delivery API readiness
Intent: Frontend teams can query and filter without bespoke server code for every page.
- Filterable fields — anything you sort or filter list pages by should be real fields (or core columns), not buried inside unstructured HTML.
- Predictable payloads — align with
ContentEntryResourceshape:fieldsobject keyed by field name; useexcludeon list requests for large bodies when supported. - List semantics —
state,locale,sort,paginate/limit/offset,where— document what your app uses; see How to Design Stable Content APIs for Frontend Teams. - Preview vs production — draft content uses the same schema; state and preview tokens are app concerns, but the schema must allow draft entries without required fields that only exist at publish time (or use sensible defaults).
6) Publishing and governance
Intent: Editors know what “done” means; developers know what breaks the build.
- Draft vs published —
stateandpublished_atare first-class on entries; required fields should apply to published content, not necessarily every draft (validate in your pipeline if the CMS allows saving incomplete drafts). - Roles and permissions — align collection usage with who can publish; sensitive collections should not share the same lax rules as marketing pages.
- Change process — renaming or removing a field is a migration: plan for existing entries, API consumers, and static caches.
7) Performance and scale
Intent: Large rich text and huge media galleries do not surprise production.
- List views — exclude heavy fields from list endpoints; load full entries only on detail routes.
- Media —
mediafields and asset options (type, etc.) should match how assets are cropped and delivered (CDN, sizes). - Repeatable blocks — cap count in editor where possible; unbounded arrays hurt authoring and payloads.
- Benchmark — run a realistic list query (page size, sort, filters) against production-like data.
Quick “go / no-go” before release
| Question | Pass / fail |
|---|---|
| Can the frontend render every required field on every template that uses this collection? | |
Are list and detail queries defined (fields used, exclude if needed)? | |
| Are locale and translation rules documented for this collection? | |
| Are singleton rules understood (one entry vs one per locale, depending on how you create entries)? | |
| Is there a migration plan for renames or type changes? |
Apply this checklist to every new collection to avoid expensive refactors later.
Related:
- Headless CMS
- How Developers Ship Faster with Headless CMS + AI
- How to Model Multilingual Content Without Duplicate Entries
- How to Design Stable Content APIs for Frontend Teams
Implementation reference (Noma Core)
- Field model —
types,required,validations,options(repeatable,hiddenInAPI,hideInContentList,relation,slug,media, …) - Content validation —
App\Http\Requests\ContentRequest(required rules, char count) - API output —
App\Http\Resources\ContentEntryResource(respectshiddenInAPI) - Collections —
is_singleton, slug, fields tree