Content › Configuration
Docs/Content/Configuration

Configuration

What you'll learn

Every option of easy-cms.config.ts: the top-level settings, collections, globals, branding and plugins.

Before this page: Getting started.

Everything about your content lives in easy-cms.config.ts at the project root:

import { defineConfig, isAdmin } from '@easy-cms/core'
import { sqlite } from '@easy-cms/db-sqlite'
 
export default defineConfig({
  secret: process.env.EASY_CMS_SECRET ?? '',
  db: sqlite({ url: 'file:./cms.db' }),
  admin: { locale: 'th' },
  collections: [
    {
      slug: 'posts',
      drafts: true,
      useAsTitle: 'title',
      access: { read: () => true, update: isAdmin },
      fields: [
        { name: 'title', type: 'text', required: true },
        { name: 'body', type: 'richText' },
      ],
    },
  ],
  globals: [{ slug: 'site', fields: [{ name: 'siteName', type: 'text' }] }],
})

defineConfig returns the config unchanged, keeping its literal types so documents can be typed from it. The config is validated at startup; every problem is reported at once with where it is and how to fix it.

Top-level options

OptionDefault
secret—Required, at least 32 characters. Signs sessions. Read it from an env var.
db—Required. A database adapter: sqlite() or postgres(). See Databases.
serverURL—Public origin such as https://example.com. Makes media URLs absolute, and is where password links point (needed for them in production).
webhooks[]Endpoints notified when content changes. See Webhooks.
cronSecretCRON_SECRETLets a cron run scheduled jobs at <api>/jobs/run. At least 32 characters.
jobs[]Your own background work, every few seconds or at a time of day. See Jobs.
timeZonethe server'sIANA zone of times of day in the config (jobs[].at, backups.at), e.g. Asia/Bangkok.
localization—{ locales, defaultLocale?, fallback? }: content in several languages (leave it out, or false, for one). See Localization.
cors[]Origins whose browser code may call the REST API, or '*' for any (anonymous requests). Origins in auth.trustedOrigins are always allowed, with cookies.
routes.api/api/cmsWhere the REST API is served.
admin.path/adminWhere the admin UI is served.
admin.localeenDefault admin language: en or th.
admin.siteURL/ (Nuxt, Next.js)The public site, for the admin's "View site" button: a path or an https:// URL.
admin.brand—{ name, logo, color }: your or your client's brand in the admin. See Branding the admin.
admin.modules[]JavaScript modules with Web Components for the admin, by package export or path; usually added by plugins.
authSee Users & auth.
uploadSee Uploads & media.
collections[]See below.
globals[]See below.
endpoints[]Custom REST endpoints: { path, method, handler }. See Plugins.
plugins[]Functions (config) => config, run in order before validation. See Plugins.

Collections

A collection is a type of content with many documents: posts, products, pages.

Option
slugURL and table name: lowercase letters, digits, -, _.
fieldsThe fields.
labels{ singular, plural }, each a string or { en, th }.
useAsTitleTop-level field shown as the document title in the admin.
admin.iconIcon in the admin menu (default file-text); one of the names under Branding the admin.
admin.orderIts place in its menu group, e.g. 1: lower first; collections without one come after, in config order. The media library comes last, user accounts are under Settings.
admin.group'settings' lists the collection under Settings in the menu (with Users and API keys) instead of with the content; false leaves it out of the menu (links still reach it). See The menu.
admin.editIn'drawer': create and edit in a panel over the list, for small collections such as categories; relationship fields to it get a "Create" button that opens the same panel. Collections with drafts, versions or preview always use the full page.
admin.list{ tree: 'parent', sort: 'title' } shows the list as a tree along a relationship to the same collection, and sets its default order.
draftsAdds status (draft | published). See Drafts.
versionstrue or { keep }: keep a version of every save, with history and restore; with drafts, drafts of published documents are kept separately. See Versions.
preview({ doc }) => url: the page that shows a document, for live preview.
admin.sidebarPanels from admin components in the edit page's side column.
schedulePublish and unpublish at a set time (needs drafts). See Scheduled publishing.
access{ read, create, update, delete }. See Access control.
hooksSee Hooks.

Every document also has id (integer), createdAt and updatedAt.

Two collections are built in: users and media. Declare a collection with the same slug to add fields, access rules or hooks to them.

Reserved slugs: admin, globals, jobs, sessions, login-attempts, document-versions, scheduled-jobs, migrations, access, auth.

Globals

A global has exactly one document: site settings, navigation, a footer.

globals: [
  {
    slug: 'site',
    label: { en: 'Site settings', th: 'ตั้งค่าเว็บไซต์' },
    access: { read: () => true },
    fields: [
      { name: 'siteName', type: 'text', defaultValue: 'My site' },
      { name: 'menu', type: 'array', fields: [{ name: 'label', type: 'text' }, { name: 'url', type: 'text' }] },
    ],
  },
],

Globals accept fields, label, drafts, versions, preview, admin (icon, order, group, sidebar, layout), access (read, update) and hooks (beforeValidate, beforeChange, afterChange, afterRead).

Branding the admin

Agencies can show their client's brand instead of Easy CMS's:

admin: {
  brand: {
    name: 'Acme Coffee',     // menu, login page and browser tab
    logo: '/acme-logo.svg',  // a path on your site or an https:// URL
    color: '#b45309',        // main color; lighter and darker shades are derived
  },
},
collections: [
  { slug: 'posts', admin: { icon: 'newspaper' }, fields: [/* … */] },
  { slug: 'menu', admin: { icon: 'utensils' }, fields: [/* … */] },
],
globals: [{ slug: 'site', admin: { icon: 'house' }, fields: [/* … */] }],

Text on the brand color turns dark when white would be hard to read. Each user picks light, dark or their system's theme in the menu.

Icons (Lucide): file-text, newspaper, book-open, notebook, folder, tag, tags, image, images, video, music, file, users, user, building, store, shopping-bag, shopping-cart, package, box, calendar, calendar-days, map-pin, globe, house, layout-grid, layers, star, heart, message-square, mail, phone, briefcase, graduation-cap, utensils, car, settings, sliders-horizontal, palette, megaphone, bell, link, quote, circle-help, award, ticket, camera, key, chart-column, chart-line.

Plugins

A plugin receives the config and returns a new one, so it can add fields, collections, endpoints and admin components:

import { seoPlugin } from '@easy-cms/plugin-seo'
 
export default defineConfig({ /* … */ plugins: [seoPlugin({ collections: ['posts'] })] })

See Plugins for the official plugins and how to write your own.

Next steps