
RocketCMS: A Zero-Model Headless CMS in Rust
Date Published
🚀 What This Post Covers
RocketCMS is an active development project - a Rust-based headless CMS with a radical philosophy: zero built-in models. Users define everything through Strapi-compatible JavaScript schemas executed via QuickJS, with APIs, migrations, and database tables generated automatically.
Zero Models, Infinite Possibilities
Most CMS platforms come with opinions. They give you users, pages, posts, media libraries - all pre-built, all rigid. RocketCMS takes a different approach: you define everything.
Phase 0 Complete: Foundation + Schema System working. The project now has a working schema parser, migration system, and dynamic API generation.
The Philosophy
📦 Traditional CMS
- Pre-built user models
- Fixed content types
- Rigid relationships
- Opinionated structure
✨ RocketCMS
- Zero built-in models
- JavaScript-defined schemas
- Dynamic migration generation
- Your structure, your rules
Architecture Overview
RocketCMS is built on proven Rust infrastructure:
Core Stack
- Axum 0.7 - Web framework with async support
- SeaORM 1.1 - Database ORM with dynamic capabilities
- Tokio - Async runtime
- rquickjs - QuickJS JavaScript engine
- PostgreSQL / SQLite - Database backends
Defining Schemas in JavaScript
Schemas are defined using Strapi-compatible JavaScript files. This was an intentional choice - it makes migration from Strapi trivial and gives users a familiar syntax.
// schemas/article.js
module.exports = {
kind: 'collectionType',
collectionName: 'articles',
info: {
singularName: 'article',
pluralName: 'articles',
displayName: 'Article',
},
attributes: {
title: {
type: 'string',
required: true,
maxLength: 200,
},
slug: {
type: 'uid',
targetField: 'title',
},
content: {
type: 'richtext',
},
published: {
type: 'boolean',
default: false,
},
author: {
type: 'relation',
relation: 'manyToOne',
target: 'api::user.user',
inversedBy: 'articles',
},
},
};
✅ Key Decision: rquickjs over Boa
The project uses rquickjs (QuickJS) instead of Boa for JavaScript execution. The reason: better ES module support and a smaller footprint, which matters when executing user code at runtime.
Dynamic Schema System
When RocketCMS starts, it:
- Loads schema files from
./src/schemas/*.js - Executes them through the QuickJS engine
- Parses the output into internal Rust structures
- Generates migrations for any schema changes
- Creates API routes automatically
⚠️ SeaORM Dynamic Research
A key question during development: Could SeaORM handle truly dynamic models without code generation? The answer: yes. SeaORM supports raw SQL execution and dynamic column access, making it perfect for schema-driven applications.
Current Implementation Status
✅ Phase 0: Foundation
- Project initialized
- Axum + SeaORM configured
- Database connections working
- 107 Rust tests passing
- 44 JavaScript vitest tests passing
✅ Phase 1: Schema System
- Schema parser implemented
- rquickjs engine wrapper
- Schema validation via Serde
- Schema loader with file watching
✅ Phase 2: Migrations
- Migration runner with 19 tests
- Schema tracking table
- Dynamic query builder
- All CRUD handlers implemented
✅ Phase 3: API Generation
- Dynamic route generation
- Request validation with garde
- Pagination support
- Response serialization
Working API Routes
The server now generates these routes automatically from schemas:
Auto-Generated Endpoints
GET /health- Health checkGET /api/health- API health checkGET /api/companies- Company listGET /api/pages- Page listGET /api/categories- Category listPOST /api/{collection}- Create itemGET /api/{collection}/:id- Read itemPATCH /api/{collection}/:id- Update itemDELETE /api/{collection}/:id- Delete item
Roadmap: What's Next
Implementation Timeline
- Phase 4: Authentication — User management, JWT tokens, password hashing, OIDC and SAML integration (likely via Keycloak)
- Phase 5: Admin Interface — React SPA with Vite for schema management, data browsing, access control editing, and user management
- Phase 6: Testing Framework — Browser tests with Chromiumoxide, self-tests on boot, and comprehensive test coverage
- Phase 7: Frontend App Management — Upload/download frontend apps as ZIPs, Git integration with Gitoxide, Docker Compose generation, and a built-in IDE
- Phase 8: Plugin System — FFI-based plugin API, dynamic loading, lifecycle management, and error isolation
Technical Highlights
⚡ Dynamic ORM
// Execute DDL dynamically
db.execute(Statement::from_string(
sea_orm::DatabaseBackend::Sqlite,
"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)"
)).await?;
// Query with dynamic results
let results = db.query_all(Statement::from_string(
sea_orm::DatabaseBackend::Sqlite,
"SELECT * FROM users".to_string(),
)).await?;
🔧 Type Mappings
| Attribute Type | SQLite Type |
|---|---|
| String, Email | TEXT |
| Integer | INTEGER |
| Boolean | INTEGER (1/0) |
| DateTime | TEXT (ISO8601) |
| Json, Enum | TEXT (JSON) |
Development Status
📊 Current Metrics
- Repository:
/data/rocketcms/ - Tests: 107 Rust tests + 44 JavaScript tests passing
- Phases Complete: 0-3 (Foundation through API Generation)
- Server Status: Running on 127.0.0.1:8080
- Status: Active development
Why This Approach Matters
Traditional CMS lock-in comes from their pre-built assumptions. By making everything user-defined, RocketCMS achieves:
Benefits
- No migration path lock-in - Bring your Strapi schemas
- No opinionated data models - Structure what you need
- No rebuild for changes - Schemas loaded at runtime
- No hardcoded relationships - Define what makes sense
- No abstraction ceiling - Full Rust performance with JavaScript ergonomics
🚀 Ready to Explore?
RocketCMS is in active development, with Phase 0-3 complete and proving the core concept works. The project demonstrates that Rust can deliver the safety and performance of a systems language while providing the developer ergonomics of JavaScript schema definition.
Next up: Authentication, admin interface, and taking the project from proof-of-concept to production-ready.