flatcms
v2.0.0
Published
A simple headless flat file CMS powered by JSON and JavaScript
Maintainers
Readme
FlatCMS
A simple headless flat-file CMS powered by JSON and JavaScript. Content lives on disk, types come from JSON Schema, and a lightweight HTMX admin UI ships in the same process.
Features
- Flat file storage: content as JSON files, organized by type
- JSON Schema validation: Ajv-backed create/update validation
- REST API: CRUD plus schema/type introspection
- Built-in admin: schema-driven forms at
/admin(EJS + vendored HTMX, no frontend build) - Nested fields: object accordions and array-of-object editors with add / duplicate / remove / drag-and-drop reorder
- MCP server:
flatcms --mcpfor agent tools, including creating complex content types - Simple auth: public reads by default; API key for writes; admin session after API-key login
- Zero database: files + configuration only
Installation
npm install flatcmsOr globally:
npm install -g flatcmsQuick Start
1. Create a .env file
API_KEY=your-secret-api-key-here
PORT=3000
CONTENT_DIR=./content
SCHEMA_FILE=./schema.jsonOptional:
SESSION_SECRET=a-long-random-string
REQUIRE_AUTH_FOR_READ=false2. Schema (schema.json)
A starter page type ships with the repo. Blocks include:
- hero — headline, intro, primary + secondary CTAs
- text — headline, text, alignment
- text_image — headline, text, image upload
- testimonials — headline, text, repeatable quotes
- video — YouTube URL or MP4 upload
- container — nested text / text+image / FAQ items for grids
You can extend or replace schema.json as needed.
3. Start the server
npm start
# or
npx flatcmsOpen http://localhost:3000/admin, sign in with your API_KEY, and manage content from the UI.
MCP mode
npx flatcms --mcpExposes stdio MCP tools for content CRUD and schema type management (create_type / update_type support nested object and array schemas). Configure in Cursor / Claude Desktop as a stdio server with API_KEY (and optional SCHEMA_FILE / CONTENT_DIR) in the environment.
Programmatic use:
const { startServer } = require('flatcms');
startServer();Or mount the Express app yourself:
const app = require('flatcms');
app.listen(3000);Configuration
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| API_KEY | yes | — | Write API + admin login |
| PORT | no | 3000 | HTTP port |
| CONTENT_DIR | no | ./content | Content root |
| SCHEMA_FILE | no | ./schema.json | JSON Schema path |
| UPLOADS_DIR | no | ./uploads | Uploaded media files |
| SESSION_SECRET | no | derived from API_KEY | Admin cookie signing secret |
| REQUIRE_AUTH_FOR_READ | no | false | If true, GET /api/* also needs the API key |
Admin UI
- URL:
/admin - Login with the same
API_KEY - Dashboard lists all content with filters and actions
- Create / edit forms are generated from each type’s JSON Schema
- Nested
objectfields render as accordions - Arrays of objects support add, duplicate, remove, and drag-and-drop reorder
- Long text (
content/body, …) uses a simple rich text editor - Optional
seoobject renders in the sidebar id,createdAt, andupdatedAtare managed automatically
No Vite/React build is required for consumers. HTMX and SortableJS are vendored under public/vendor/.
MCP tools
| Tool | Purpose |
|------|---------|
| list_types | List content types |
| get_schema | Full schema or one type |
| list_content / get_content | Read content |
| create_content / update_content / delete_content | Write content |
| create_type / update_type / delete_type | Manage schema definitions (including complex nested types) |
Content Storage
content/
├── post/
│ └── <id>.json
└── page/
└── <id>.jsonEach item includes id, createdAt, and updatedAt.
API Authentication
Include the API key as:
Authorization: Bearer <API_KEY>- or
X-API-Key: <API_KEY>
v2 defaults:
GET/HEAD/OPTIONSon/api/*are public (unlessREQUIRE_AUTH_FOR_READ=true)POST/PUT/DELETEalways require the API key
List content
GET /api/content/:type?limit=&offset=&sort=updatedAt|createdAt&order=asc|descGet one item
GET /api/content/:type/:idCreate
POST /api/content/:type
Content-Type: application/jsonUpdate
PUT /api/content/:type/:id
Content-Type: application/jsonDelete
DELETE /api/content/:type/:idTypes & schema
GET /api/types
GET /api/schema
GET /api/schema/:typeHealth
GET /healthNo authentication required.
Error Responses
{
"error": "Error message",
"details": []
}Common status codes: 400, 401, 404, 409, 500.
License
ISC
