@natilon/astro-cms
v1.0.0
Published
Astro integration that mounts the Natilon CMS admin under /admin during `astro dev` and exposes content helpers.
Maintainers
Readme
@natilon/astro-cms
Astro integration for Natilon CMS. Mounts the CMS admin panel into astro dev, auto-generates content collection config, and exports the JSON loader + schema builder your site needs.
Install
npm i @natilon/astro-cms @natilon/cms-serverQuick start
1. Create cms.config.mjs
export default {
mountPath: "/admin",
locales: ["en"],
defaultLocale: "en",
collections: {
blog: {
label: "Blog Posts",
listFields: ["title", "pubDate"],
metaFields: [
{ key: "title", type: "text", label: "Title", required: true },
{ key: "slug", type: "text", label: "Slug", required: true },
{ key: "pubDate", type: "datetime", label: "Published" },
{ key: "blocks", type: "blocks", label: "Content" },
],
},
},
content: {
pagesDir: "src/pages-data",
publishBranch: "main",
commitMessage: (ts) => `Content updated ${ts}`,
},
media: { provider: "local" },
auth: {
provider: "basic",
userEnv: "ADMIN_USER",
passEnv: "ADMIN_PASS",
},
};2. Mount in astro.config.mjs
import { defineConfig } from "astro/config";
import natilon from "@natilon/astro-cms";
import config from "./cms.config.mjs";
export default defineConfig({
integrations: [natilon({ config })],
});3. Run astro dev — src/content.config.ts is generated automatically
✔ Generated src/content.config.ts — covers blog. Edit freely.The generated file covers every collection in cms.config.mjs. You can commit it, and adding a new collection to cms.config.mjs requires no changes to it. Delete it to regenerate.
4. Add env vars (.env)
ADMIN_USER=admin
ADMIN_PASS=secret5. Render blocks in your pages
---
import BlockRenderer from "@natilon/astro-blocks";
const { entry } = Astro.props;
---
<BlockRenderer blocks={entry.data.blocks} />See @natilon/astro-blocks for the full block reference.
cms.config.mjs reference
Collection options
collections: {
blog: {
label: "Blog Posts", // displayed in sidebar
listFields: ["title", "slug"], // columns shown in entry list
metaFields: [ ... ], // editable fields
defaultValues: { draft: true },
},
}metaFields field types
| type | Editor control | Zod type (auto) |
|------------------|---------------------------------------|------------------------------|
| text | Single-line input | z.string().optional() |
| textarea | Multi-line input | z.string().optional() |
| richtext | Rich-text editor (HTML output) | z.string().optional() |
| number | Numeric input | z.number().optional() |
| boolean | Toggle | z.boolean().optional() |
| date | Date picker | z.coerce.date().optional() |
| datetime | Date + time picker | z.coerce.date().optional() |
| select | Dropdown (options: [...] required) | z.enum([...]).optional() |
| image | Media picker (CDN or local) | z.string().optional() |
| meta-image | OG/social image picker | z.string().nullable().optional() |
| json | Raw JSON textarea | z.unknown().optional() |
| collection-ref | Entry picker from another collection | z.string().optional() |
| blocks | Block content editor (see astro-blocks)| auto-included always |
| code | Code editor | z.string().optional() |
Options:
{ key: "status", type: "select", label: "Status", options: ["draft", "published"], required: true }
{ key: "cover", type: "image", label: "Cover image" }
{ key: "source", type: "collection-ref", label: "Author", collection: "authors" }required: true shows a red * in the editor and blocks saving if the field is empty.
Custom block types
// cms.config.mjs — optional, extends the built-in block palette
blocks: {
hero: {
label: "Hero",
icon: "fa-star",
properties: {
heading: { type: "text", label: "Heading", required: true },
image: { type: "image", label: "Background image" },
cta: { type: "text", label: "Button text" },
ctaHref: { type: "text", label: "Button URL" },
},
defaults: { heading: "Welcome" },
},
},Content helpers
jsonContentLoader and buildCollectionSchema are re-exported from the main entry:
import { jsonContentLoader, buildCollectionSchema } from "@natilon/astro-cms";jsonContentLoader(collection, opts?)
Astro Content Layer loader. Reads src/pages-data/{collection}/*.json (or opts.pagesDir).
loader: jsonContentLoader("blog")
loader: jsonContentLoader("blog", { pagesDir: "content/pages" })buildCollectionSchema(collectionConfig, { z })
Generates a Zod schema from a collection's metaFields. Always includes slug, lang, draft, publishAt, blocks, and standard taxonomy arrays.
// Extend to tighten types:
schema: buildCollectionSchema(config.collections.blog, { z }).extend({
pubDate: z.coerce.date(), // make date required (not optional)
}),Integration options
| Option | Type | Default |
|--------------------|------------|---------------------------------|
| config | Object | required — your cms.config |
| publicConfig | Function | auto-derived (strips secrets) |
| rootDir | string | Astro's config.root |
| adminUiSourceDir | string | path to admin-ui for HMR dev |
| realm | string | HTTP Basic auth realm |
