Content Mode Configuration

Learn how to configure Content Mode with content.config.json to define collections, templates, and output paths.

Basic Configuration Structure

The content.config.json file uses JSON syntax to define your collections and how they're processed. Here's the basic structure:

{
  "collections": {
    "collectionName": {
      "path": "content/path",
      "template": "templates/template.html",
      "output": {
        "filename": "output/{{ slug }}/index.html"
      },
      "fields": { ... }
    }
  }
}

Each collection is defined as an object within the collections object, with the collection name as the key.

Collection Configuration Options

path (required)

The directory where content files are located, relative to your project root.

"path": "content/posts"

format (optional)

The file format for content files. Options: "md", "yaml", or "yml". Defaults to "md" if not specified.

"format": "md"

template (optional)

The template file to use for rendering content, relative to your project root.

"template": "templates/post.html"

output (new format)

Output configuration object that defines where generated pages are written.

"output": {
  "filename": "blog/{{ slug }}/index.html"
}

The filename property supports template syntax with {{ slug }}, {{ date }}, or any field from your content.

slug (optional)

Slug generation configuration.

"slug": {
  "field": "title",
  "fallback": "filename"
}
  • field: Which field to use for slug generation (default: "title")
  • fallback: What to use if the field is missing (default: filename)

fields (optional)

Field definitions for validation and type checking. See the Field Types section below for details.

styleGuide (optional)

Natural language description for AI-assisted authoring. Used by AI IDEs (like Cursor) to provide context when creating content.

"styleGuide": "Blog posts should be engaging, informative, and between 500-2000 words."

Field Types

Field types define the structure and validation for your content. Available types:

string

Single-line text field.

"title": {
  "type": "string",
  "required": true
}

text

Multi-line text field.

"summary": {
  "type": "text",
  "required": false
}

markdown

Markdown content field.

"body": {
  "type": "markdown",
  "required": true
}

datetime

Date and time field (ISO 8601 format).

"date": {
  "type": "datetime",
  "required": true
}

boolean

True/false field.

"published": {
  "type": "boolean",
  "required": false
}

number

Numeric value field.

"price": {
  "type": "number",
  "required": true
}

array

List of values field.

"tags": {
  "type": "array",
  "required": false
}

relation

Reference to another collection. See Relations section below.

image

Image file reference.

"avatar": {
  "type": "image",
  "required": false
}

Field Configuration

Fields can be configured with validation rules and options:

{
  "fields": {
    "title": {
      "type": "string",
      "required": true
    },
    "author": {
      "type": "relation",
      "collection": "authors",
      "valueField": "slug"
    },
    "summary": {
      "type": "text",
      "required": false
    }
  }
}

Required Fields

Set "required": true to enforce that a field must be present in content files. Missing required fields will generate warnings during build.

Optional Fields

Set "required": false or omit the required property to make a field optional.

Relations

Relations allow you to link content items across collections, creating relationships like posts → authors or products → categories.

Defining Relations

Define a relation field in your collection configuration:

{
  "fields": {
    "author": {
      "type": "relation",
      "collection": "authors",
      "valueField": "slug"
    }
  }
}

Using Relations in Content

In your content files, reference related content by slug:

---
title: "My Post"
author: "authors/john"
---

Using Relations in Templates

In templates, relations are automatically resolved to full document objects:

<!-- $doc.author.name -->
<!-- $doc.author.bio -->
<!-- $doc.author.avatar -->
Tip: Relations are resolved during build time. If a relation reference is broken (the target doesn't exist), you'll get a warning but the build will continue.

Complete Example

Here's a complete example configuration for a blog with posts and authors:

{
  "collections": {
    "posts": {
      "path": "content/posts",
      "format": "md",
      "template": "templates/post.html",
      "output": {
        "filename": "blog/{{ slug }}/index.html"
      },
      "slug": {
        "field": "title",
        "fallback": "filename"
      },
      "fields": {
        "title": { "type": "string", "required": true },
        "date": { "type": "datetime", "required": true },
        "author": {
          "type": "relation",
          "collection": "authors",
          "valueField": "slug"
        },
        "tags": { "type": "array" }
      }
    },
    "authors": {
      "path": "content/authors",
      "format": "yaml",
      "template": "templates/author.html",
      "output": {
        "filename": "authors/{{ slug }}/index.html"
      }
    }
  }
}

Next Steps

Now that you understand configuration, learn about: