Areca Docs

Defining your content

Describe your collections, fields and identifiers in areca.config.ts, with the validation rules the SDK and CMS enforce.

Your content model lives in areca.config.ts, at the root of the website project. It lists the kinds of content your site has, such as articles or authors, and the fields editors fill in for each one. You push this file to the CMS with areca manifest push, and the CMS then shows the same collections and fields to editors.

In the CMS, a collection is called a content type. This guide uses "collection" throughout, because that is the name in the code.

The config file uses defineSiteContent. It checks the config at compile time, so your editor shows a mistake as you type it, and it returns the config unchanged. The rules are listed in authoring rules below.

An example: articles and authors

This example has two collections. Each article points to one author, which is a reference.

areca.config.ts
import { defineSiteContent } from '@areca-cms/site-sdk'

export default defineSiteContent({
  siteKey: 'acme-site',
  collections: {
    authors: {
      route: '/authors/$slug',
      label: 'Authors',
      fields: [
        { key: 'name', label: 'Name', type: 'text', required: true },
        { key: 'bio', label: 'Bio', type: 'textarea' },
        { key: 'photo', label: 'Photo', type: 'image' },
      ],
    },
    articles: {
      route: '/blog/$slug',
      label: 'Articles',
      fields: [
        { key: 'title', label: 'Title', type: 'text', required: true },
        { key: 'excerpt', label: 'Excerpt', type: 'textarea' },
        { key: 'body', label: 'Body', type: 'richtext', required: true },
        { key: 'cover', label: 'Cover image', type: 'image' },
        { key: 'author', label: 'Author', type: 'reference', collection: 'authors' },
        {
          key: 'category',
          label: 'Category',
          type: 'select',
          options: ['news', 'guides', 'updates'],
        },
        { key: 'publishedOn', label: 'Published on', type: 'date' },
        { key: 'updatedOn', label: 'Updated on', type: 'date', after: 'publishedOn' },
      ],
    },
  },
})

Areca adds a required slug field as the first field of every collection, so you do not need to declare one. Each entry's slug is used in URLs, and route tells the CMS where entries live on your site. See slug values.

Top-level options

OptionRequiredDescription
siteKeyYesThe key of the CMS site, as shown on the site's Developer tab. areca init and areca manifest pull use it. The push does not send it, because the schema token already identifies the site.
collectionsYesAn object whose keys are collection keys and whose values are collection definitions. It can be empty.
globalsNoAn object whose keys are site content section keys, such as companyInfo. Each section holds a single set of values, not a list. See site content.

Collection options

OptionRequiredDescription
routeYesThe frontend route pattern for entries, such as /blog/$slug. It must contain $slug, which is replaced by each entry's slug. It can be up to 500 characters. The SDK records the pattern for the CMS, but it does not generate routes. You still write the route in your framework.
labelNoThe name editors see in the CMS, such as "Articles". It can be up to 200 characters. If you omit it, the CMS shows the collection key.
fieldsYesThe list of fields. A collection can have up to 100 fields.

Field options

Each entry in fields is an object with these options:

OptionRequiredDescription
keyYesThe identifier for the field. It is the name of the field's value in pulled data. In your code it becomes camelCase, so cover_image is coverImage. See identifiers.
labelYesThe label editors see. It can be up to 200 characters.
typeYesOne of the twelve field types, such as text, richtext or reference. See field types for each one.
requiredNoSet to true to require a value. Editors can save a draft without it, but the entry cannot be marked ready or go live until they fill it in.
descriptionNoHelp text shown to editors. It can be up to 1,000 characters.
optionsOnly for selectThe choices for a select field. Up to 200 options, each up to 200 characters. Other types do not accept it.
collectionYes for reference, otherwise not allowedThe key of the collection the reference can point to. It must be a collection key of the same config. Your editor suggests the keys as you type.
afterOnly for date and datetimeThe key of another date or datetime field in the same collection. This value must be on or after that field's value. Your editor suggests only the keys of date fields.
groupNo, and only in site contentA heading shown above the field in the editor, such as Contact. Consecutive fields with the same heading share it. The SDK value stays flat. Collection fields may not set group. See site content.

The SDK checks identifiers before it sends anything. The CMS validates the whole manifest when it receives it, including the length and count limits above.

Authoring rules

defineSiteContent enforces the first five rules with the TypeScript compiler, so your editor reports a mistake as you type. The last rule is checked when you push or pull:

  • type is one of the twelve field types. Your editor suggests them.
  • Options depend on the type. options is only allowed on select. collection is required on reference, and only allowed there. after is only allowed on date and datetime.
  • References point at real collections. A reference's collection must be the key of a collection in the same config. Your editor suggests those keys.
  • after names a date field. It must be the key of a date or datetime field in the same collection. Your editor suggests only those keys.
  • Routes contain $slug. A collection's route must include the text $slug, so each entry has its own URL.
  • Keys are identifiers. The SDK checks them against the identifier rules when you push or pull, as described above.
areca.config.ts
import { defineSiteContent } from '@areca-cms/site-sdk'

export default defineSiteContent({
  siteKey: 'acme-site',
  collections: {
    authors: {
      route: '/authors', // error: a route must contain $slug
      fields: [{ key: 'name', label: 'Name', type: 'text', required: true }],
    },
    articles: {
      route: '/blog/$slug',
      fields: [
        { key: 'author', label: 'Author', type: 'reference', collection: 'writers' }, // error: no collection called writers
        { key: 'category', label: 'Category', type: 'text', options: ['news'] }, // error: options only on select
        { key: 'updatedOn', label: 'Updated on', type: 'date', after: 'title' }, // error: title is not a date field
      ],
    },
  },
})

Identifiers

Identifiers are the names you choose for collections and fields: the keys of collections, the key of each field, and any collection or after value that points to another one. They have these rules:

  • They start with an ASCII letter. After that they can contain letters, digits, _ and -.
  • They are at most 64 characters long.
  • They must not be a reserved name. The reserved names are __proto__, prototype, constructor, manifest, con, prn, aux, nul, com1 to com9, and lpt1 to lpt9. The check ignores case, so MANIFEST is reserved too.
  • A collection key or site content key must not be resolve, href, preview, globals or previewGlobals. Camel-cased forms count too, so preview-globals is refused. The content object in your code uses those names for its own methods. This check ignores case. Field keys may use these names.
  • A field key must be unique within its collection.
  • In your code, keys are camelCase, so two keys that differ only in their dashes or underscores (blog-posts and blog_posts) collide. The pull refuses them. See typed content.

Identifiers are also used as names in the output. Each collection becomes a file named after its key, such as articles.json. For that reason, pick names that you will keep.

Two rules follow from this:

  • Renaming a collection key creates a new collection. The old one is disabled on the next push. Its entries stay in the CMS but are no longer published.
  • Renaming a field key does not move values. Existing values stay under the old key, and the new field starts empty. Editors need to re-enter the value.

If an identifier breaks the rules, areca manifest push stops with an error such as Unsafe collection or field identifier, and it does not send the manifest.

Slug values

Entries and slug fields have a second, separate rule: the value must be lowercase letters and digits, with single hyphens between parts. There are no leading or trailing hyphens, and the value can be up to 200 characters. Examples: hello-world, 2026-roadmap.

Site content sections

Site content sections go under globals, beside collections. They use the same field options, with two differences: a section has no slug field, and a field may set group. A section can also set label, seo (default false) and previewPath. See site content for the full example and rules.

Changing the config

Edit areca.config.ts and run areca manifest push. The push replaces the definition of each collection or site content section it lists, and it disables any it leaves out. Disabled sections keep their content. For what happens to existing content, see syncing the schema.

If your collections were created in the CMS, you can copy them into a config file with areca manifest pull. See CLI reference.

On this page