Content model
What MagiCMS is storing
MagiCMS is a CMS for Astro sites. It does not keep content in a private database. It reads and writes JSON files in your Git repository. Astro builds the public site from those files.
Three ideas cover almost everything:
- A schema lists the fields MagiCMS should show in the editor.
- A content type is a kind of thing you edit (a page, a collection entry, a site-wide setting).
- A block is a reusable section on a page (hero, text, cards, and so on).
You define the shape. MagiCMS draws the forms. Astro renders the result.
Schema
A schema is a JSON object that names each field, its type, and options such as translatable or required. The same field types are used for blocks, collections, globals, sections and page types.
When you change a schema in MagiCMS, you are changing what editors can fill in — and the shape of the JSON Astro will receive. Field keys are the names in that JSON. Renaming a key does not migrate old content; treat keys as part of the contract.
The list of types, and when to pick each one, is on Schema field types.
{ "label": "Team member", "fields": { "name": { "type": "text", "translatable": true, "required": true }, "photo": { "type": "image", "ratio": "1:1" }, "bio": { "type": "richtext", "translatable": true } }}Pages: structure and translation
A page is one URL. MagiCMS stores it as two kinds of files:
src/content/pages/<slug>.structure.json— layout, the tree of blocks (and optional sections), and values that are not translated (layout name, some flags, image paths if the field is not translatable).src/content/pages/<slug>.<lang>.json— copy for one language, keyed by each block’s_id.
The slug is the filename. The home page slug is set in site.config.json as homeSlug (often home) and is served at /.
Astro loads the structure, merges the language file, and renders the blocks. You rarely read these files by hand; MagiCMS is the editor. You do need to know they exist, because they are what Git records.
// about.structure.json — tree and non-translated values{ "layout": "Article", "blocks": [ { "_type": "Hero", "_id": "hero-1" }, { "_type": "Richtext", "_id": "body-1" } ]}
// about.en.json — English copy for those block ids{ "hero-1": { "heading": "About us" }, "body-1": { "body": "<p>We build Astro sites.</p>" }}Blocks
A block is a visual unit on a page. In the project it is a folder: an Astro component plus a schema, for example src/blocks/Hero/Hero.astro and Hero.schema.json. Names are PascalCase.
MagiCMS lets you install blocks from a library, add them to a page, reorder them, and edit their fields. Installing a block copies it into your project. After that, the copy is yours — you can change the Astro markup. MagiCMS can also reload the library version, which overwrites local changes to that block.
Most blocks render in the page body. A few target the document <head> (for example SEO). That is a schema setting called target, not something you pick per instance.
How install and reload work is on Block library. Do not start by cataloguing every block — the library in the editor is the list that applies to your project.
Sections
A section is an optional wrapper around a group of blocks. The scaffold ships a Theme section: it sets a daisyUI data-theme on that group so part of a page can use a different palette.
Sections sit between the layout and the blocks. They have their own schema (same field types, no target). If a page has no sections, MagiCMS still works — a flat list of blocks is valid.
Collections
A collection is a repeating content type: team members, articles, products. You define the schema once. Each item is an entry with a slug.
Files live under src/content/<name>/: <name>.schema.json, then <slug>.json plus optional <slug>.<lang>.json for translations.
Astro already has a route for every collection: /<collection>/<slug>. You do not add a custom route per collection unless you change the scaffold.
This is different from a schema field of type collection, which is a reference to one entry (a slug stored on a block). See Schema field types.
src/content/team/ team.schema.json // the shape of every member _order.json // optional display order ada.json // shared / default-language values ada.nb.json // Norwegian overlay, if you use nbGlobals
A global is a singleton: one record for the whole site, not a list of URLs. Typical uses are site name and theme, cookie banner copy, and an icon catalog.
The scaffold creates site, cookie and icons. You can add more (header, footer, shared strings) with a schema of your own. MagiCMS edits one global at a time; there is no “entry list”.
Astro reads them with a helper such as loadGlobal('site', lang). A select field on a block can reuse a list from a global (for example icon ids) — that is optionsFromGlobal on the schema.
Page types
A page type is extra schema for children of a navigation item, not a replacement for pages. You attach it on the parent in Navigation (childSchema).
Example: this documentation section. The parent “Docs” uses a Documentation page type. Each child page then has fields such as title and excerpt, and can default to the Documentation layout. MagiCMS still stores a normal page (structure + language files); the page type is the extra meta and the default layout for those children.
Use a page type when a group of pages shares the same extra fields (docs, case studies, a directory). Use a collection when items are not ordinary pages in the nav tree (a team grid, a news index with many entries).
Navigation
Navigation is not a sixth content type in the same sense, but it is site-wide JSON: src/content/navigation.json. It is a tree of slugs (or external URLs), per-language labels, and flags such as whether an item appears in the menu.
The tree can nest a few levels. Child pages of a typed parent inherit that page type. MagiCMS edits this in the Navigation view; the public site’s header reads the same file.
How to work day to day in the editor is on Using MagiCMS.