Features / Model

Schemas without migrations

One JSON5 file in types/ and the collection exists — API, admin form and validation included. Field types, conditions, partials and rules in one file, hot-reloaded without a restart.

Validation checks every entry against its schema and reports the result
Validation checks every entry against its schema and reports the result

You need a new collection. In most systems that means writing a migration, touching the database, deploying. In RustyCMS you drop a JSON5 file into types/. The watcher picks it up, and from then on the collection exists — REST endpoints, admin form, validation. Change a field and it applies immediately.

One file, one collection

// types/blog_post.json5
{
  name: "blog_post",
  strict: true,
  fields: {
    title:      { type: "string", required: true, maxLength: 200 },
    body:       { type: "content", format: "markdown", required: true },
    tags:       { type: "array", items: { type: "string" } },
    author:     { type: "reference", collection: "person" },
    published:  { type: "boolean", default: false },
    created_at: { type: "datetime", auto: true, readonly: true },
  }
}

Field types: string, number, integer, boolean, datetime, array, object, reference (polymorphic across several collections if needed), referenceOrInline, multiSelect with enum, image and file with a MIME whitelist. Text gets type: "content" with a format of markdown, richtext, html or plain — that decides editor and rendering. HTML is sanitized on save: no <script>, no on* handlers, unless you deliberately loosen it.

Fields that only appear when they’re needed

showIf shows a field in the admin form when a sibling field has a certain value — the date only for type: "event", the teaser for everything else. Editors see only what belongs to the chosen type. API and validation are untouched; the field is always stored.

date: { type: "datetime", showIf: { field: "type", eq: "event" } },

Define once, use everywhere

A schema with reusable: true is a partial: layout options, SEO fields, an address block. Any other schema pulls it into an object field via useFields. extends inherits whole schemas, one or several; pick, omit and partial trim the result. strict: true rejects unknown fields on write instead of silently carrying them along.

Validation that doesn’t wait for the frontend

required, min/max, minLength/maxLength, pattern, enum, unique, minItems/maxItems — nested down into array items. Checked in three places: on write through the API, via the validate CLI with no server running (exit code 1 on errors, so it fits into CI), and in the admin UI, where every failing entry links straight to its editor.

validate --content-dir ./content --collections post,page

Autocomplete in your editor

One export writes a JSON Schema file per content type. VS Code or Cursor then check content files as you type — required fields, enum values, length limits as squiggles before anything is saved.

What doesn’t happen

A schema change never rewrites existing entries. Renaming or deleting a field is a migration — deliberately separate, so no edit to one file silently alters content.

Want to see this on your own project?

Tell me briefly what you're planning. I'll show the admin UI on a real installation and say honestly whether it fits.

Request early access