Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/alineacms/alinea/llms.txt

Use this file to discover all available pages before exploring further.

Your cms.ts (or cms.tsx) file is the single source of truth for your entire content model. Everything Alinea needs to know — which entry types exist, how they are organized, where files live on disk, and how the dashboard behaves — is declared here and passed to createCMS. The TypeScript types flow from this config directly into your query layer, so your editor autocomplete and runtime data stay in sync.

The Config object

createCMS from alinea/next accepts a plain object that satisfies the Config interface. Every field is type-checked at call time, and createCMS automatically validates cross-references — for example, that types named in contains arrays actually exist in the schema — at startup.
Shape of Config
interface Config {
  /** A schema describing the types of entries */
  schema: Schema

  /** A record containing workspace configurations */
  workspaces: Record<string, Workspace>

  /** Named roles for access control */
  roles?: Record<string, Role>

  /** Embed a live-preview URL inside the dashboard */
  preview?: Preview

  /** Every edit passes through a draft status before publishing */
  enableDrafts?: boolean

  /** Interval in seconds at which the frontend polls for updates */
  syncInterval?: number

  /** Base URL of the application — can differ per environment */
  baseUrl?: string | { development?: string; production?: string }

  /** URL of the Alinea handler endpoint */
  handlerUrl?: string

  /** Folder where public assets are stored — defaults to /public */
  publicDir?: string

  /** Filename of the generated dashboard HTML — defaults to admin.html */
  dashboardFile?: string

  /** Authentication view rendered in the dashboard */
  auth?: Auth.View
}
createCMS automatically injects the CloudAuthView as the default auth value and merges the built-in admin role into roles. You only need to override these if you want custom behavior.

Minimal example

The example below shows a complete, working cms.ts for a Next.js project with two entry types and one workspace.
cms.ts
import {Config, Field} from 'alinea'
import {createCMS} from 'alinea/next'

// --- Entry types ---

const BlogPost = Config.document('Blog post', {
  fields: {
    intro: Field.text('Introduction', {multiline: true}),
    body: Field.richText('Body')
  }
})

const Blog = Config.document('Blog', {
  contains: [BlogPost],
  fields: {}
})

// --- Schema ---

const schema = Config.schema({
  types: {Blog, BlogPost}
})

// --- CMS ---

export const cms = createCMS({
  schema,
  handlerUrl: '/api/cms',
  baseUrl: {
    development: 'http://localhost:3000',
    production: 'https://example.com'
  },
  enableDrafts: true,
  workspaces: {
    main: Config.workspace('Main', {
      source: 'content/main',
      mediaDir: 'public',
      roots: {
        pages: Config.root('Pages', {
          contains: [Blog]
        }),
        media: Config.media()
      }
    })
  }
})
Export cms as a named export so you can import it in both your Next.js route handler (/api/cms/route.ts) and your page components for typed queries.

Config options reference

schema
Schema
required
The assembled schema object returned by Config.schema(). Contains all entry type definitions and is the foundation for typed queries.
workspaces
Record<string, Workspace>
required
A map of workspace keys to workspace objects created with Config.workspace(). Every key must be a valid identifier ([A-Za-z0-9_]).
roles
Record<string, Role>
Additional named roles for access control. Create roles with Config.role(label, options), which accepts a permissions callback receiving a WriteablePolicy to define fine-grained allow/deny rules. An admin role with full access is always included automatically.
const editor = Config.role('Editor', {
  permissions(policy) {
    policy.set({allow: {read: true}})
  }
})

export const cms = createCMS({
  roles: {editor},
  // ...
})
preview
Preview
When set to true or a URL string, Alinea embeds a live-preview frame inside the dashboard. Can also be configured per workspace or per root.
enableDrafts
boolean
default:"false"
When true, every save creates a draft entry that must be explicitly published before it appears to public queries.
syncInterval
number
How often (in seconds) the dashboard polls the backend for content updates.
baseUrl
string | { development?: string; production?: string }
The public URL of your application. Used to construct entry preview URLs. Supply an object to use different values per NODE_ENV.
handlerUrl
string
The URL of the Alinea API route handler. Defaults to /api/cms when using createHandler from alinea/next.
publicDir
string
default:"/public"
The folder where uploaded public assets are written. Passed through to the file backend.
dashboardFile
string
default:"admin.html"
Filename of the generated dashboard HTML file. The dashboard is served at the path derived from this name (e.g. admin.html/admin).
auth
Auth.View
The authentication view component rendered in the dashboard login screen. Defaults to CloudAuthView.

Explore the configuration layers

The config is split into four closely related concepts. Read each guide to understand the full picture.

Workspaces

Group roots together and point them at a source directory on disk.

Roots

Define the top-level entry points inside a workspace’s content tree.

Types & Fields

Describe the shape of every entry with typed field definitions.

Build docs developers (and LLMs) love