Copied to clipboard!

Master Vibe CMS's field system to build flexible, type-safe content schemas. This chapter provides comprehensive coverage of field types, interface options, validation, and best practices for schema design.

Understanding the Field System

Every collection in Vibe CMS is defined by its fields. Fields determine what data can be stored, how it's validated, and how content editors interact with it in the admin interface.

Each field has two critical properties:

  • Field Type: The data type stored in the database (text, markdown, number, boolean, file)
  • Interface Type: The UI component used for editing (input, textarea, markdown, single_file, multiple_files)

Field Types Deep Dive

text

The text field type stores string data. It's the most versatile field type, suitable for any text content from short labels to long descriptions.

Storage: PostgreSQL text column in the data JSONB field Use Cases:

  • Titles and headlines
  • Names and labels
  • Descriptions and summaries
  • Short-form content
  • URL slugs and identifiers

Validation: No length limits at the database level, but interface types may enforce constraints

Example Schema:

{
  field_name: "title",
  field_type: "text",
  interface_type: "input",  // Single-line input
  is_required: true
}

Compatible Interfaces: input, textarea

markdown

The markdown field type stores markdown-formatted text, ideal for rich content that needs structure, formatting, and embedded media.

Storage: PostgreSQL text column containing markdown syntax Use Cases:

  • Blog post content
  • Article bodies
  • Documentation pages
  • Rich descriptions with formatting
  • Content requiring headings, lists, links, images

Validation: Markdown syntax is stored as-is; validation happens at render time

Example Schema:

{
  field_name: "content",
  field_type: "markdown",
  interface_type: "markdown",  // Rich markdown editor
  is_required: true
}

Compatible Interfaces: markdown (only)

Note: The markdown interface typically provides a live preview, syntax highlighting, and toolbar for common formatting operations.

number

The number field type stores numeric data, including integers and floating-point values.

Storage: PostgreSQL numeric type in JSONB Use Cases:

  • Prices and monetary values
  • Quantities and counts
  • Ratings and scores
  • Sort orders and priorities
  • Statistical data

Validation: Must be a valid numeric value; additional constraints can be added at the application level

Example Schema:

{
  field_name: "price",
  field_type: "number",
  interface_type: "input",
  is_required: false
}

Compatible Interfaces: input (only)

boolean

The boolean field type stores true/false values, perfect for flags, toggles, and binary states.

Storage: PostgreSQL boolean in JSONB Use Cases:

  • Feature flags (is_featured, is_published)
  • User preferences (email_notifications_enabled)
  • State toggles (is_active, is_archived)
  • Conditional logic (show_author, enable_comments)

Validation: Must be exactly true or false

Example Schema:

{
  field_name: "is_featured",
  field_type: "boolean",
  interface_type: "input",  // Checkbox or toggle switch
  is_required: false
}

Compatible Interfaces: input (only)

Default Behavior: Boolean fields typically default to false if not specified.

file

The file field type stores references to files in Vibe CMS's file management system. Files themselves are stored in Supabase Storage; fields contain file IDs.

Storage: PostgreSQL uuid (single_file) or uuid[] array (multiple_files) Use Cases:

  • Featured images and thumbnails
  • PDF downloads and attachments
  • Media galleries
  • Document libraries
  • Profile pictures and avatars

Validation: File IDs must reference valid files in the cms_files table

Single File Example:

{
  field_name: "featured_image",
  field_type: "file",
  interface_type: "single_file",
  is_required: false
}

Multiple Files Example:

{
  field_name: "gallery",
  field_type: "file",
  interface_type: "multiple_files",
  is_required: false
}

Compatible Interfaces: single_file, multiple_files

File References: When querying content, file fields return file IDs. Use the SDK's asset manager to resolve file URLs and metadata.

Interface Types Explained

Interface types control how content editors interact with fields in the admin UI. Each field type supports specific interfaces.

input

Single-line text input field, appropriate for short strings and simple values.

Compatible Field Types: text, number, boolean Renders As:

  • Text: <input type="text">
  • Number: <input type="number">
  • Boolean: <input type="checkbox"> or toggle switch

Best For: Titles, names, identifiers, simple values

textarea

Multi-line text input area for longer plain-text content.

Compatible Field Types: text (only) Renders As: <textarea> element with resizable height Best For: Descriptions, notes, plain-text content spanning multiple lines

Note: Use textarea for plain text; use markdown interface for formatted content.

markdown

Rich markdown editor with live preview, syntax highlighting, and formatting toolbar.

Compatible Field Types: markdown (only) Renders As: Split-pane editor with markdown input and HTML preview Features:

  • Syntax highlighting
  • Live preview
  • Formatting toolbar (bold, italic, links, etc.)
  • Image insertion
  • Code block support

Best For: Blog posts, articles, documentation, any content requiring rich formatting

single_file

File picker interface that allows selecting one file from the file library.

Compatible Field Types: file (only) Renders As: File browser with thumbnail preview and upload button Interaction: Click to open file library, select one file, or upload new file Best For: Featured images, single attachments, profile pictures

multiple_files

File picker interface that allows selecting multiple files from the file library.

Compatible Field Types: file (only) Renders As: File browser with thumbnail grid and multi-select capability Interaction: Click to open file library, select multiple files, drag to reorder Best For: Image galleries, document collections, media libraries

Field Configuration

Required vs Optional Fields

Fields can be marked as required or optional using the is_required property:

{
  field_name: "title",
  field_type: "text",
  interface_type: "input",
  is_required: true  // Content cannot be published without this field
}

Required Fields (is_required: true):

  • Must be provided before content can be saved or published
  • Enforced at the API level during content creation/update
  • Indicated with visual markers in the admin UI

Optional Fields (is_required: false):

  • Can be left empty
  • No validation errors if omitted
  • Useful for supplementary metadata

Best Practice: Mark only essential fields as required. Over-requiring fields creates friction for content editors.

Field Naming Conventions

Field names must follow strict database naming rules:

Rules:

  • Must start with a lowercase letter (a-z)
  • Can contain lowercase letters, numbers, and underscores
  • Cannot contain spaces, hyphens, or special characters
  • Must be unique within the collection

Valid Examples:

  • title
  • featured_image
  • publish_date
  • author_name
  • meta_description

Invalid Examples:

  • Title (uppercase)
  • featured-image (hyphen)
  • publish date (space)
  • 1st_item (starts with number)

Reserved Names: The following field names are reserved and cannot be used:

  • id, created_at, updated_at
  • data, metadata
  • select, from, where, insert, update, delete, table
  • SQL keywords and system columns

Regex Pattern: ^[a-z][a-z0-9_]*$

Sort Order for Field Display

The sort_order property controls the order in which fields appear in the admin interface:

{
  field_name: "title",
  field_type: "text",
  interface_type: "input",
  is_required: true,
  sort_order: 0  // First field
}

Ordering:

  • Lower numbers appear first (0, 1, 2, ...)
  • Fields with the same sort_order are ordered by creation date
  • Sort order can be any non-negative integer

Best Practice: Use increments of 10 (0, 10, 20, ...) to leave room for inserting fields later.

Field Metadata

Every field in the database includes these properties:

{
  id: "uuid",                    // Unique field ID
  collection_id: "uuid",         // Parent collection
  account_id: "uuid",            // Owner account
  field_name: "title",           // Database column name
  field_type: "text",            // Data type
  interface_type: "input",       // UI component
  is_required: false,            // Validation flag
  sort_order: 0,                 // Display order
  created_at: "2025-01-15T10:30:00Z",
  updated_at: "2025-01-15T10:30:00Z",
  created_by: "uuid",            // User who created field
  updated_by: "uuid"             // User who last modified field
}

MCP Tools for Field Management

Vibe CMS provides MCP (Model Context Protocol) tools for programmatic field management. These tools are ideal for AI agents and automation scripts.

add_collection_field

Creates a new field in a collection.

Parameters:

{
  collection_slug: "blog-posts",    // Collection identifier
  name: "author_name",              // Field name (lowercase, valid identifier)
  field_type: "text",               // One of: text, markdown, number, boolean, file
  interface_type: "input",          // Must be compatible with field_type
  is_required: false,               // Optional, defaults to false
  sort_order: 10                    // Optional, defaults to 0
}

Example:

await mcp.add_collection_field({
  collection_slug: "blog-posts",
  name: "excerpt",
  field_type: "text",
  interface_type: "textarea",
  is_required: false,
  sort_order: 20
});

Validation:

  • Field name must follow naming conventions
  • Field name must be unique in collection
  • Interface type must be compatible with field type
  • Sort order must be non-negative

update_collection_field

Modifies an existing field's properties. Field name and field type typically cannot be changed after creation.

Parameters:

{
  collection_slug: "blog-posts",
  field_name: "excerpt",
  interface_type: "textarea",       // Optional: change UI component
  is_required: true,                // Optional: change required status
  sort_order: 15                    // Optional: change display order
}

Example:

await mcp.update_collection_field({
  collection_slug: "blog-posts",
  field_name: "excerpt",
  is_required: true,
  sort_order: 15
});

Limitations:

  • Changing field_name may break existing content
  • Changing field_type is typically not allowed
  • Changing interface_type must maintain compatibility

reorder_collection_fields

Changes the display order of all fields in a collection at once.

Parameters:

{
  collection_slug: "blog-posts",
  field_names: ["title", "excerpt", "content", "author_name"]  // Complete ordered list
}

Example:

await mcp.reorder_collection_fields({
  collection_slug: "blog-posts",
  field_names: [
    "title",
    "author_name",
    "excerpt",
    "content",
    "featured_image",
    "publish_date"
  ]
});

Requirements:

  • Must include ALL fields in the collection
  • Fields are assigned sort_order 0, 1, 2, ... based on array position
  • Missing fields will cause an error

delete_collection_field

Permanently removes a field from a collection, including all data in that field across all content items.

Parameters:

{
  collection_slug: "blog-posts",
  field_name: "old_field",
  confirm: true                     // Must be true to confirm deletion
}

Example:

await mcp.delete_collection_field({
  collection_slug: "blog-posts",
  field_name: "deprecated_field",
  confirm: true
});

Warning:

  • This operation is IRREVERSIBLE
  • All content data in this field will be permanently deleted
  • Use with extreme caution in production

Field Combinations and Patterns

text + input: Short Text

Perfect for single-line string values like titles, names, and labels.

{
  field_name: "title",
  field_type: "text",
  interface_type: "input",
  is_required: true,
  sort_order: 0
}

Use Cases: Page titles, product names, author names, category labels

text + textarea: Long Text

Ideal for multi-line plain text like descriptions and notes.

{
  field_name: "description",
  field_type: "text",
  interface_type: "textarea",
  is_required: false,
  sort_order: 10
}

Use Cases: Product descriptions, meta descriptions, internal notes, plain-text summaries

markdown + markdown: Rich Content

The standard pattern for formatted content like blog posts and articles.

{
  field_name: "content",
  field_type: "markdown",
  interface_type: "markdown",
  is_required: true,
  sort_order: 20
}

Use Cases: Blog posts, documentation, article bodies, formatted descriptions

file + single_file: Single Image/Document

For content that needs one featured image or attachment.

{
  field_name: "featured_image",
  field_type: "file",
  interface_type: "single_file",
  is_required: false,
  sort_order: 30
}

Use Cases: Featured images, hero images, profile pictures, single PDF downloads

file + multiple_files: Galleries and Collections

For content requiring multiple files like image galleries or document libraries.

{
  field_name: "gallery",
  field_type: "file",
  interface_type: "multiple_files",
  is_required: false,
  sort_order: 40
}

Use Cases: Photo galleries, document libraries, portfolio items, product image sets

Best Practices

When to Use Each Field Type

text:

  • Any string data
  • When you need flexibility between single-line and multi-line input
  • SEO fields (meta title, meta description)
  • Identifiers and slugs

markdown:

  • Long-form content requiring formatting
  • Content with headings, lists, links, images
  • Documentation and articles
  • Any content that benefits from structure

number:

  • Numeric values for calculations or comparisons
  • Prices, quantities, ratings
  • Sort orders and priorities
  • Statistical data

boolean:

  • Binary states and flags
  • Feature toggles
  • Enable/disable settings
  • Conditional logic in templates

file:

  • Images, videos, documents
  • Media that needs professional asset management
  • Content requiring file metadata (alt text, captions)
  • Downloads and attachments

Field Naming Strategies

1. Use descriptive, self-documenting names:

// Good
field_name: "author_bio"
field_name: "publish_date"
field_name: "featured_image"

// Bad
field_name: "text1"
field_name: "data"
field_name: "field"

2. Use consistent prefixes for related fields:

field_name: "meta_title"
field_name: "meta_description"
field_name: "meta_keywords"

3. Avoid abbreviations unless universally understood:

// Good
field_name: "url"
field_name: "seo_title"

// Bad
field_name: "desc"  // Use "description"
field_name: "img"   // Use "image"

4. Use underscores for multi-word names:

field_name: "call_to_action_text"  // Good
field_name: "callToActionText"     // Bad (camelCase not allowed)

Schema Design Patterns

1. Core Content Pattern:

// Essential fields first
{ field_name: "title", field_type: "text", interface_type: "input", sort_order: 0 }
{ field_name: "slug", field_type: "text", interface_type: "input", sort_order: 10 }
{ field_name: "content", field_type: "markdown", interface_type: "markdown", sort_order: 20 }

// Media and metadata
{ field_name: "featured_image", field_type: "file", interface_type: "single_file", sort_order: 30 }
{ field_name: "publish_date", field_type: "text", interface_type: "input", sort_order: 40 }

// SEO fields last
{ field_name: "meta_title", field_type: "text", interface_type: "input", sort_order: 50 }
{ field_name: "meta_description", field_type: "text", interface_type: "textarea", sort_order: 60 }

2. E-commerce Product Pattern:

{ field_name: "product_name", field_type: "text", interface_type: "input", is_required: true }
{ field_name: "sku", field_type: "text", interface_type: "input" }
{ field_name: "price", field_type: "number", interface_type: "input", is_required: true }
{ field_name: "description", field_type: "markdown", interface_type: "markdown" }
{ field_name: "images", field_type: "file", interface_type: "multiple_files" }
{ field_name: "in_stock", field_type: "boolean", interface_type: "input" }

3. Author/Team Member Pattern:

{ field_name: "full_name", field_type: "text", interface_type: "input", is_required: true }
{ field_name: "role", field_type: "text", interface_type: "input" }
{ field_name: "bio", field_type: "markdown", interface_type: "markdown" }
{ field_name: "profile_picture", field_type: "file", interface_type: "single_file" }
{ field_name: "email", field_type: "text", interface_type: "input" }
{ field_name: "is_featured", field_type: "boolean", interface_type: "input" }

Migration and Schema Changes

Planning Schema Changes:

  1. Additive changes are safe: Adding new optional fields doesn't break existing content
  2. Removing fields is destructive: Always back up data before deleting fields
  3. Renaming is risky: Rename = delete + create, which loses data
  4. Type changes are dangerous: Changing field types may corrupt existing data

Safe Migration Pattern:

// 1. Add new field
await mcp.add_collection_field({
  collection_slug: "blog-posts",
  name: "new_field",
  field_type: "text",
  interface_type: "input",
  is_required: false
});

// 2. Migrate data programmatically (if needed)
const posts = await cms.collection("blog-posts").all();
for (const post of posts) {
  // Transform and update content
}

// 3. Mark old field as deprecated (or delete if truly unused)
// Note: No "deprecated" flag exists; use naming convention like "old_field_deprecated"

Risky Migration Pattern (avoid if possible):

// Renaming a field = delete old + create new = DATA LOSS
// Instead: Create new field, migrate data, then delete old field

Validation Strategies

1. Use is_required for essential fields:

{ field_name: "title", is_required: true }      // Cannot publish without title
{ field_name: "excerpt", is_required: false }   // Optional enhancement

2. Implement application-level validation for complex rules:

  • Email format validation
  • URL format validation
  • Character limits
  • Regex pattern matching
  • Cross-field dependencies

3. Use field types to enforce basic data types:

  • number ensures numeric values
  • boolean ensures true/false
  • file ensures valid file references

4. Leverage interface types for UX-driven validation:

  • input for short text
  • textarea for long text
  • markdown for structured content

Database Schema Reference

The cms_collection_fields table structure:

CREATE TABLE cms_collection_fields (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  collection_id UUID NOT NULL REFERENCES cms_collections(id) ON DELETE CASCADE,
  account_id UUID NOT NULL REFERENCES basejump.accounts(id) ON DELETE CASCADE,
  field_name TEXT NOT NULL,
  field_type TEXT NOT NULL CHECK (field_type IN ('text', 'markdown', 'number', 'boolean', 'file')),
  interface_type TEXT NOT NULL CHECK (interface_type IN ('input', 'textarea', 'markdown', 'single_file', 'multiple_files')),
  is_required BOOLEAN NOT NULL DEFAULT false,
  sort_order INTEGER NOT NULL DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  created_by UUID REFERENCES auth.users(id),
  updated_by UUID REFERENCES auth.users(id),
  
  UNIQUE (collection_id, field_name)
);

Key Constraints:

  • field_type must be one of: text, markdown, number, boolean, file
  • interface_type must be one of: input, textarea, markdown, single_file, multiple_files
  • field_name must be unique within the collection
  • Cascade deletion: removing a collection deletes all its fields

Field Type Compatibility Matrix

Field Type Compatible Interfaces Use Cases
text input, textarea Titles, descriptions, labels, plain text
markdown markdown Blog posts, articles, rich content
number input Prices, quantities, ratings, counts
boolean input Flags, toggles, true/false states
file single_file, multiple_files Images, documents, media assets

Summary

This chapter covered:

  • Five field types: text, markdown, number, boolean, file
  • Five interface types: input, textarea, markdown, single_file, multiple_files
  • Field configuration: Required fields, naming conventions, sort order
  • MCP tools: add_collection_field, update_collection_field, reorder_collection_fields, delete_collection_field
  • Common patterns: Schema design for blogs, products, team members
  • Best practices: Naming, validation, migrations, schema evolution

With this knowledge, you can design flexible, type-safe content schemas that meet your application's needs while providing an excellent editing experience.

Next Steps


Need Help? Visit the Troubleshooting Guide or join our Discord community.