Docs/cms/Content Types

Content Types

Define custom content types with the schema builder. Learn about all 20 field types, nested structures, and configuration options.


What Are Content Types?

Content types define the structure of your content. A content type is a named schema with a set of field definitions — think of it as a blueprint for a category of documents. For example, you might create content types for blog posts, products, team members, FAQ entries, or landing pages.

Each content type stores its field definitions as a JSON array. When you create or edit a document, R3 CMS compiles these definitions into validation rules and auto-generates the editing form.

Content Type Structure

Every content type has the following metadata:

PropertyRequiredDescription
nameYesUnique identifier, used in API queries (e.g., blog_post)
labelYesHuman-readable display name (e.g., "Blog Post")
descriptionNoHelp text shown in the content type list
iconNoIcon name for the sidebar
slugFieldNoWhich field to auto-generate the URL slug from
titleFieldNoWhich field displays as the document title in list views

Field Definition Schema

Each field in a content type follows this structure:

{
  "name": "title",
  "label": "Title",
  "type": "text",
  "required": true,
  "description": "The main heading for this document",
  "defaultValue": null
}
PropertyRequiredDescription
nameYesAPI key for the field (e.g., title, featuredImage)
labelYesDisplay name shown in the editor
typeYesOne of the 20 supported field types
requiredYesWhether the field must have a value
descriptionNoHelp text shown below the field in the editor
defaultValueNoDefault value when creating a new document
configNoType-specific configuration options

Additional properties depend on the field type — see the type-specific sections below.

Field Types Reference

text

Single-line string input. Use for titles, names, short labels.

{ "name": "title", "label": "Title", "type": "text", "required": true }

textarea

Multi-line string input with auto-sizing. Use for descriptions, excerpts, plain-text content.

{ "name": "excerpt", "label": "Excerpt", "type": "textarea", "required": false }

richText

Full-featured rich text editor powered by TipTap. Stores content as TipTap JSON. Supports formatting, links, images, and embeds.

{ "name": "body", "label": "Body", "type": "richText", "required": true }

number

Integer or floating-point number input.

{ "name": "price", "label": "Price", "type": "number", "required": true }

boolean

Toggle switch for true/false values.

{ "name": "featured", "label": "Featured", "type": "boolean", "required": false, "defaultValue": false }

date

Date picker that stores an ISO date string (e.g., 2026-03-25).

{ "name": "eventDate", "label": "Event Date", "type": "date", "required": true }

datetime

Date and time picker that stores an ISO datetime string (e.g., 2026-03-25T10:00:00.000Z).

{ "name": "scheduledFor", "label": "Scheduled For", "type": "datetime", "required": false }

image

Image upload with drag-and-drop and preview. Files are stored on R2/S3. The field value is the uploaded URL.

{ "name": "featuredImage", "label": "Featured Image", "type": "image", "required": true }

file

General file upload. Files are stored on R2/S3. The field value is the uploaded URL.

{ "name": "attachment", "label": "Attachment", "type": "file", "required": false }

slug

Auto-generated URL slug from a source field. Only allows lowercase letters, numbers, and hyphens.

{ "name": "slug", "label": "Slug", "type": "slug", "sourceField": "title" }

The sourceField property specifies which field to generate the slug from (e.g., "My Blog Post" becomes my-blog-post).

select

Dropdown with predefined options.

{
  "name": "status",
  "label": "Priority",
  "type": "select",
  "required": true,
  "options": [
    { "label": "Low", "value": "low" },
    { "label": "Medium", "value": "medium" },
    { "label": "High", "value": "high" }
  ]
}

reference

Link to another content document. Renders as an async search field in the editor.

{
  "name": "category",
  "label": "Category",
  "type": "reference",
  "referTo": ["blog_category"]
}

The referTo array specifies which content type(s) can be referenced. The stored value is the UUID of the referenced document.

array

Repeatable list of items where each item has the same fields. Supports drag-and-drop reordering.

{
  "name": "features",
  "label": "Features",
  "type": "array",
  "minItems": 1,
  "maxItems": 10,
  "itemFields": [
    { "name": "title", "label": "Feature Title", "type": "text", "required": true },
    { "name": "description", "label": "Feature Description", "type": "textarea", "required": true },
    { "name": "icon", "label": "Icon", "type": "text", "required": false }
  ]
}

object

Nested group of fields. Renders as a collapsible fieldset. Use for grouping related data like SEO metadata or address information.

{
  "name": "seo",
  "label": "SEO Metadata",
  "type": "object",
  "fields": [
    { "name": "metaTitle", "label": "Meta Title", "type": "text", "required": false },
    { "name": "metaDescription", "label": "Meta Description", "type": "textarea", "required": false },
    { "name": "ogImage", "label": "OG Image", "type": "image", "required": false }
  ]
}

blocks

Typed repeatable blocks where each block can have a different structure. Ideal for flexible page builders where sections have different layouts.

{
  "name": "sections",
  "label": "Page Sections",
  "type": "blocks",
  "blocks": [
    {
      "name": "hero",
      "label": "Hero Section",
      "fields": [
        { "name": "heading", "label": "Heading", "type": "text", "required": true },
        { "name": "subheading", "label": "Subheading", "type": "textarea", "required": false },
        { "name": "backgroundImage", "label": "Background Image", "type": "image", "required": true }
      ]
    },
    {
      "name": "textBlock",
      "label": "Text Block",
      "fields": [
        { "name": "content", "label": "Content", "type": "richText", "required": true }
      ]
    },
    {
      "name": "cta",
      "label": "Call to Action",
      "fields": [
        { "name": "heading", "label": "CTA Heading", "type": "text", "required": true },
        { "name": "buttonText", "label": "Button Text", "type": "text", "required": true },
        { "name": "buttonUrl", "label": "Button URL", "type": "url", "required": true }
      ]
    }
  ]
}

Each block item stores a _type field indicating which block definition it uses.

json

Raw JSON editor for arbitrary structured data.

{ "name": "metadata", "label": "Custom Metadata", "type": "json", "required": false }

color

Color picker that stores a hex color value (e.g., #3b82f6).

{ "name": "brandColor", "label": "Brand Color", "type": "color", "required": false }

url

URL input with built-in validation.

{ "name": "website", "label": "Website", "type": "url", "required": false }

email

Email input with built-in validation.

{ "name": "contactEmail", "label": "Contact Email", "type": "email", "required": false }

tags

Tag input that stores an array of strings. Renders with an autocomplete UI for adding and removing tags.

{ "name": "tags", "label": "Tags", "type": "tags", "required": false }

Example Content Type Definitions

Blog Post

{
  "name": "blog_post",
  "label": "Blog Post",
  "slugField": "title",
  "titleField": "title",
  "icon": "file-text",
  "fields": [
    { "name": "title", "label": "Title", "type": "text", "required": true },
    { "name": "excerpt", "label": "Excerpt", "type": "textarea", "required": false },
    { "name": "body", "label": "Body", "type": "richText", "required": true },
    { "name": "featuredImage", "label": "Featured Image", "type": "image", "required": true },
    { "name": "category", "label": "Category", "type": "reference", "referTo": ["blog_category"] },
    { "name": "tags", "label": "Tags", "type": "tags" },
    {
      "name": "seo",
      "label": "SEO",
      "type": "object",
      "fields": [
        { "name": "metaTitle", "label": "Meta Title", "type": "text", "required": false },
        { "name": "metaDescription", "label": "Meta Description", "type": "textarea", "required": false }
      ]
    }
  ]
}

Product

{
  "name": "product",
  "label": "Product",
  "slugField": "name",
  "titleField": "name",
  "icon": "shopping-bag",
  "fields": [
    { "name": "name", "label": "Product Name", "type": "text", "required": true },
    { "name": "description", "label": "Description", "type": "richText", "required": true },
    { "name": "price", "label": "Price", "type": "number", "required": true },
    { "name": "image", "label": "Product Image", "type": "image", "required": true },
    { "name": "inStock", "label": "In Stock", "type": "boolean", "required": false, "defaultValue": true },
    {
      "name": "variants",
      "label": "Variants",
      "type": "array",
      "itemFields": [
        { "name": "variantName", "label": "Variant Name", "type": "text", "required": true },
        { "name": "variantPrice", "label": "Variant Price", "type": "number", "required": true },
        { "name": "sku", "label": "SKU", "type": "text", "required": true }
      ]
    }
  ]
}

FAQ

{
  "name": "faq",
  "label": "FAQ",
  "slugField": "question",
  "titleField": "question",
  "icon": "help-circle",
  "fields": [
    { "name": "question", "label": "Question", "type": "text", "required": true },
    { "name": "answer", "label": "Answer", "type": "richText", "required": true },
    { "name": "sortOrder", "label": "Sort Order", "type": "number", "required": false, "defaultValue": 0 },
    { "name": "category", "label": "Category", "type": "select", "options": [
      { "label": "General", "value": "general" },
      { "label": "Billing", "value": "billing" },
      { "label": "Technical", "value": "technical" }
    ]}
  ]
}

Landing Page (with Blocks)

{
  "name": "landing_page",
  "label": "Landing Page",
  "slugField": "title",
  "titleField": "title",
  "icon": "layout",
  "fields": [
    { "name": "title", "label": "Page Title", "type": "text", "required": true },
    {
      "name": "sections",
      "label": "Page Sections",
      "type": "blocks",
      "blocks": [
        {
          "name": "hero",
          "label": "Hero",
          "fields": [
            { "name": "heading", "label": "Heading", "type": "text", "required": true },
            { "name": "subheading", "label": "Subheading", "type": "textarea", "required": false },
            { "name": "backgroundImage", "label": "Background", "type": "image", "required": true },
            { "name": "ctaText", "label": "CTA Text", "type": "text", "required": false },
            { "name": "ctaUrl", "label": "CTA Link", "type": "url", "required": false }
          ]
        },
        {
          "name": "features",
          "label": "Features Grid",
          "fields": [
            { "name": "heading", "label": "Section Heading", "type": "text", "required": true },
            {
              "name": "items",
              "label": "Feature Items",
              "type": "array",
              "itemFields": [
                { "name": "featureTitle", "label": "Title", "type": "text", "required": true },
                { "name": "featureDescription", "label": "Description", "type": "textarea", "required": true },
                { "name": "featureIcon", "label": "Icon", "type": "text", "required": false }
              ]
            }
          ]
        },
        {
          "name": "richContent",
          "label": "Rich Text Section",
          "fields": [
            { "name": "content", "label": "Content", "type": "richText", "required": true }
          ]
        }
      ]
    },
    {
      "name": "seo",
      "label": "SEO Settings",
      "type": "object",
      "fields": [
        { "name": "metaTitle", "label": "Meta Title", "type": "text", "required": false },
        { "name": "metaDescription", "label": "Meta Description", "type": "textarea", "required": false },
        { "name": "ogImage", "label": "Social Image", "type": "image", "required": false }
      ]
    }
  ]
}

Creating Content Types via API

You can also create content types programmatically. See the API Reference for full details.

curl -X POST https://cms.yourdomain.com/api/content-types \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "blog_post",
    "label": "Blog Post",
    "slugField": "title",
    "titleField": "title",
    "fields": [
      { "name": "title", "label": "Title", "type": "text", "required": true },
      { "name": "body", "label": "Body", "type": "richText", "required": true }
    ]
  }'