Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mdcms.ai/llms.txt

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

Config file

The CLI reads its configuration from mdcms.config.ts at the project root. Use defineConfig and defineType from @mdcms/cli to get full type safety.
mdcms.config.ts
import { defineConfig, defineType, reference } from "@mdcms/cli";
import { z } from "zod";

const Author = defineType("Author", {
  directory: "content/authors",
  fields: {
    name: z.string().min(1),
    bio: z.string().optional(),
    avatar: z.string().url().optional(),
    twitter: z.string().optional(),
  },
});

const BlogPost = defineType("BlogPost", {
  directory: "content/blog",
  localized: true,
  fields: {
    title: z.string().min(1).max(200),
    slug: z.string().regex(/^[a-z0-9-]+$/),
    author: reference("Author"),
    publishedAt: z.coerce.date(),
    tags: z.array(z.string()).default([]),
    featured: z.boolean().default(false),
    excerpt: z.string().max(300).optional(),
  },
});

export default defineConfig({
  project: "marketing-site",
  serverUrl: "https://cms.example.com",
  environment: "development",
  contentDirectories: ["content"],
  locales: {
    default: "en",
    supported: ["en", "fr", "de"],
    aliases: {
      "en-US": "en",
      "en-GB": "en",
    },
  },
  types: [Author, BlogPost],
  environments: {
    staging: {
      serverUrl: "https://cms-staging.example.com",
    },
    production: {
      serverUrl: "https://cms.example.com",
    },
  },
  components: [
    { name: "Callout", importPath: "@/components/Callout" },
    { name: "CodeBlock", importPath: "@/components/CodeBlock" },
  ],
});

Config options

All properties accepted by defineConfig:
PropertyTypeRequiredDescription
projectstringYesProject slug. Must match the project on the server
serverUrlstringYesBase URL of the MDCMS server
environmentstringNoDefault environment name (e.g. development)
contentDirectoriesstring[]NoDirectories to scan for content files. Default: ["content"]
localesobjectNoLocale configuration (see below)
typesMdcmsTypeDefinition[]NoContent type definitions created with defineType
environmentsRecord<string, object>NoPer-environment config overlays (can override serverUrl, environment)
componentsobject[]NoMDX component registrations for the Studio editor

Locale options

PropertyTypeDescription
locales.defaultstringThe default locale code (e.g. "en")
locales.supportedstring[]All supported locale codes
locales.aliasesRecord<string, string>Map alternate locale codes to canonical ones

Type definition options

Each defineType(name, options) accepts:
PropertyTypeDescription
directorystringFilesystem directory for this type’s content files
localizedbooleanWhether documents of this type are localized. Default: false
fieldsRecord<string, ZodSchema>Frontmatter field definitions using Zod schemas

Environment files

The CLI loads .env* files before importing mdcms.config.ts, so config files can read values from process.env:
mdcms.config.ts
export default defineConfig({
  serverUrl: process.env.MDCMS_SERVER_URL,
  project: process.env.MDCMS_PROJECT,
  environment: process.env.MDCMS_ENVIRONMENT ?? "development",
  types: [BlogPost],
});
Env files are read from the directory that contains the resolved mdcms.config.ts, mdcms.config.js, or mdcms.config.mjs. If you pass --config ./config/mdcms.config.ts, the CLI looks for env files in ./config. Without --config, the CLI searches upward from the current directory for the nearest config file. Put local developer values in .env.local next to mdcms.config.ts:
.env.local
MDCMS_SERVER_URL=http://localhost:4000
MDCMS_PROJECT=marketing-site
MDCMS_ENVIRONMENT=staging
MDCMS_API_KEY=mdcms_key_local
Loading order, highest precedence first:
OrderFileWhen loaded
1.env.{NODE_ENV}.localAlways
2.env.localExcept when NODE_ENV=test
3.env.{NODE_ENV}Always
4.envAlways
NODE_ENV is only the dotenv file selector. It controls names such as .env.production; it does not select the MDCMS content environment. Use MDCMS_ENVIRONMENT or the config environment field to choose an MDCMS environment such as staging or production.
NODE_ENV defaults to development when unset. Shell-exported variables override all file values, so CI secrets and one-off command exports always win. Use --no-env-file or MDCMS_DOTENV=0 to disable automatic env file loading for a run.

Manifest file

The manifest tracks the mapping between server documents and local files. It is stored at .mdcms.manifest.json in the project root, scoped to the current project and environment.
The manifest file should be added to .gitignore. It contains local state that varies between developers and environments.

Structure

The manifest is a JSON object where each key is a documentId and the value describes the local file:
.mdcms.manifest.json
{
  "doc_a1b2c3d4": {
    "path": "content/blog/hello-world.en.mdx",
    "format": "mdx",
    "draftRevision": 3,
    "publishedVersion": 1,
    "hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
  },
  "doc_e5f6g7h8": {
    "path": "content/authors/jane-doe.md",
    "format": "md",
    "draftRevision": 1,
    "publishedVersion": null,
    "hash": "sha256:abc123..."
  }
}
FieldTypeDescription
pathstringRelative path to the content file from project root
format"md" | "mdx"File format
draftRevisionnumberCurrent draft revision number on the server
publishedVersionnumber | nullPublished version number, or null if never published
hashstringContent hash of the file at last sync

Schema state

After each mdcms schema sync, the CLI writes a state file to:
.mdcms/schema/<project>.<environment>.json
For example, marketing-site project in the development environment produces:
.mdcms/schema/marketing-site.development.json

Contents

.mdcms/schema/marketing-site.development.json
{
  "schemaHash": "a1b2c3d4e5f6...",
  "syncedAt": "2026-04-13T10:30:00.000Z",
  "serverUrl": "https://cms.example.com"
}
The schemaHash is required by mdcms push to validate that content is being pushed against the correct schema version. If this file is missing or the hash is stale, push operations will fail.
The .mdcms/ directory should be added to .gitignore. The mdcms init wizard does this automatically.

File mapping

The CLI maps server documents to local files based on the type’s directory setting and the document’s path and locale.

Localized documents

Localized types produce files with the locale code inserted before the file extension:
<directory>/<path>.<locale>.<ext>
For example, a BlogPost document with path hello-world, locale en, and format mdx:
content/blog/hello-world.en.mdx
The same document in French:
content/blog/hello-world.fr.mdx

Non-localized documents

Non-localized types use a simpler pattern without the locale segment:
<directory>/<path>.<ext>
For example, an Author document with path jane-doe and format md:
content/authors/jane-doe.md