Define the shape of independent content#
A content type is a tenant-level schema for records that editors manage independently. Create one for an Article, Product, Author, FAQ, Location, or site-wide settings record.
Each entry created from the type belongs to a website and a language. The type itself is shared by the tenant, which keeps a model consistent across websites when that is what your organization needs.
Pick Collection or Single#
| Kind | Use it when | Example |
|---|---|---|
Collection | Editors need many entries of the same shape | article, product, author |
Single | There should be one entry per website and language | site_settings, footer_content |
Contoprix enforces the Single rule when an entry is created: one active entry for that content type, website, and language. Choose Collection for anything that will have a list or detail route.
Plan before adding fields#
Ask one simple question: what can an editor change without asking a developer? The answer should become a field. Do not put a temporary visual preference in a general-purpose content type when it only belongs to one page block.
For example:
| Need | Best model choice |
|---|---|
| A reusable Article record | Content type |
| A hero layout on a page | Component type |
| An Article's author | Relation to an Author entry |
| An image selected from the library | Media/Image field |
| Several editorially ordered feature rows | Repeater or component field |
Worked example: Article#
Create a Collection content type with:
| Setting | Recommended value |
|---|---|
| Name | Article |
| Code | article |
| Draft support | On |
| Version support | On |
| Localization | On only when articles will exist in more than the default language |
Then add these fields:
| Name | Code | Field type | Required | Why |
|---|---|---|---|---|
| Title | title | Text | Yes | Main headline |
| Slug | slug | Slug | Yes | Stable delivery lookup and route value |
| Summary | summary | Text Area | No | Card and search description |
| Body | body | Rich Text | No | Long-form copy |
| Hero image | heroImage | Image | No | Media-library asset |
| Author | author | Relation | No | Reusable Author entry |
The slug field has special value: Contoprix reads a field with the exact code slug and uses it as the entry's delivery slug. Slugs are normalized to lowercase without leading/trailing slashes and must be unique for the same website, content type, and language.
Use field types that match the meaning#
Contoprix has many field types. Start with the type that represents the content meaning, not the one that seems fastest to render today.
| Content you need | Good field type | Avoid |
|---|---|---|
| Short label or headline | Text | Rich text for a one-line label |
| Multi-line plain copy | Text Area | A long text value crammed into Text |
| Editor-authored formatted body | Rich Text or Markdown | Rendering untrusted HTML yourself |
| URL-safe identifier | Slug | Asking editors to manually keep a Text field URL-safe |
| One or several choices | Select, Multi Select, Radio, Checkbox | Free text when values must be consistent |
| Numeric amount or score | Number, Decimal, Currency, Rating | Text followed by frontend parsing |
| Asset from the media library | Image, File, Gallery, Media, Video, Audio | Copying an asset URL into Text |
| Another CMS record | Relation or Multi Relation | Repeating an author or product name in text |
Use Group, Object, and Repeater when a set of fields belongs together. Use a Component field when the nested structure should reuse a particular component schema. Use a Dynamic Zone when editors may choose among a deliberately limited set of component types.
Name and code fields deliberately#
| Property | Who sees it | Example | Change policy |
| --- | --- | --- |
| Name | Editors | Hero image | Can be improved for clarity |
| Code | SDK, generated types, frontend mappers | heroImage | Treat as stable API contract |
Codes are unique within the same parent field level. Use a consistent convention such as lower camel case (heroImage) or snake case (hero_image) and keep it consistent across a project.
Warning
Changing a field code does not magically update application code. Add a replacement field, support both values during migration, update entries, and remove the old field only after no frontend code reads it.
Required, optional, and validation rules#
Mark a field required only when an entry cannot be useful without it. A title is usually required; a hero image often is not. For every optional field, define the frontend behavior before you publish the model:
{article.heroImage ? (
<img src={article.heroImage.url} alt={article.heroImage.alt ?? ""} />
) : null}Use validation for length, numeric bounds, and patterns where content rules truly need them. Make editor-facing descriptions specific, for example: “Use 140 characters or fewer for card layouts.”
See the model in delivery#
After creating an Article and publishing an entry, the SDK response looks like this:
const entry = await client.content.getBySlug("article", "hello-contoprix");
const article = entry.data as {
title?: string;
slug?: string;
summary?: string;
};
console.log(article.title);The content-type code is passed to the SDK method. Every model field is nested inside entry.data using its field code.
Test a type before scaling it#
- Create the type and one realistic entry.
- Fill required values and intentionally leave an optional value empty.
- Publish the entry.
- Fetch it from the frontend using the type code and slug.
- Confirm the UI handles full, sparse, and missing data safely.
- If your team uses the CLI, run
contoprix pull,contoprix generate, andcontoprix validateafter the schema change.
Next, learn Component Types for reusable UI blocks or Relations to link Articles to Authors without copying data.