The contentModels object defines a few model-related settings that our UI needs, but are not set within model definitions (due to separation of concerns).

This includes:

  1. Which model types are listed when the "Add New Page" button is clicked in the UI, where in the filesystem to store these new pages (when using the default Git CMS), and the mapping between files and URLs.
  2. Which non-page models (e.g. Person) can be added via the UI, and where to store added content.

Generally, only model types which the UI should allow adding need to be listed.

Example

stackbitVersion: ~0.4.0
# ...
dataDir: content/data
pagesDir: content/pages
# ...
contentModels:
  PageLayout:
    isPage: true
    urlPath: '/{slug}'
    newFilePath: '{slug}.md'
  PostLayout:
    isPage: true
    urlPath: '/blog/{slug}'
    newFilePath: 'posts/{slug}.md'
  Person:
    newFilePath: 'team/{slug}.json'

Properties

isPage

For each of the model names in this list, this property controls whether the UI will allow instantiating that model as a page. The default is false.

When this is true, you may need to also define urlPath.

newFilePath

This only applies to Git CMS.

Stackbit stores new pages at {pagesDir}/{newFilePath} and non-pages under {dataDir}/{newFilePath}.

Supported File Formats

New content files are formatted according to the file extension you set. Supported formats include:

  • json
    newFilePath: '{slug}.json'
    # => "hello-world.json"
    
  • md
    newFilePath: '{slug}.md'
    # => "hello-world.md"
    
  • toml
    newFilePath: '{slug}.toml'
    # => "hello-world.toml"
    
  • yaml
    newFilePath: '{slug}.yaml'
    # => "hello-world.yaml"
    

Using Variables

These property is meant to be dynamic, based on input from the editor, and therefore supports variable interpolation. The following are supported:

  • title: The title, manually set by the editor.
    newFilePath: '{title}.md'
    # => "Hello World.md"
    
  • slug: The slug field, manually set by the editor.
    newFilePath: '{slug}.json'
    # => hello-world.json
    
  • moment_format: A formatted version of today's date using Moment.js formats. Note: Use date as the first argument with this option.
    newFilePath: "posts/{moment_format(date, 'YYYY-MM-DD')}-{slug}.yaml"
    # => posts/2022-02-22-hello-world.yaml
    

urlPath

Default URL mapping

By default, the UI will that any page content maps to URLs using their slug. This has the same meaning as explicitly setting: urlPath: '/{slug}'.

With the built-in Git based CMS, the slug is simply the path to the file relative to pagesDir, excluding the file extension.

Continuing with the examples above, the file content/pages/about.md whose type is PageLayout will be mapped to the URL /about , and vice versa.

When should I explicitly set the URL path?

As long as the file structure under pagesDir matches the URL structure of your website, there's no need. However, if the structure differs for some models, you will typically need to set both urlPath and newFilePath.

For example, here's how to define that blog posts should be saved under posts/<post-name>.md, but their URL should be /blog/<post-name>:

contentModels:
  # ...
  PostLayout:
    isPage: true
    urlPath: '/blog/{slug}'
    newFilePath: 'posts/{slug}.md'

Automatic handling of index pages

The UI has special handling for index pages:

  • When a user adds a new page and sets its path it /plans/ (note the trailing slash!), the page content will be stored to the file /content/pages/plans/index.md
  • When you navigate to this page, the UI will know to map the URL /plans/ back to /content/pages/plans/index.md.

Configuring URL paths for an API-based CMS

The slug concept is common in many CMS systems and site generators. It's a special field which is used to map the content item to a URL. The slug may be automatically generated from another field (e.g. the title) or it could be manually set. Typically, the field holding the slug is simply called slug as well.

By default, urlPath is set to '/{slug}'. This means URLs are mapped directly to the slug field in the content piece, but you can specify another field name instead.

One common need is to tweak the urlPath depending on the model type, e.g. for all content items of type Post in the CMS, setting urlPath: '/blog/{slug}'.