The headless CMS built for Astro
Composable block-based pages, reusable content, hierarchical menus, and a visual editor — all self-hosted and open source. Install in minutes, deploy anywhere.
$ npx create-wolly my-site
Creating project in ./my-site...
$ cd my-site && npm run migrate && npm run seed
$ npm run dev
WollyCMS running at http://localhost:4321
Admin UI at http://localhost:4321/admin
Features
Everything you need to build content-driven sites
A complete CMS with the composition power of Drupal, the editing experience of Storyblok, and the simplicity you actually want.
Block Composition
Build pages from typed, reusable blocks arranged in named regions. Hero, content, sidebar, features — you define the layout, editors fill in the blocks.
Astro-Native
First-class @wollycms/astro package with typed client, BlockRenderer component, menu helpers, image optimization, and SEO utilities.
Reusable Block Library
Create a block once, use it on any page. Edit once, updates everywhere. Usage tracking prevents accidental deletion.
Visual Page Builder
Drag-and-drop blocks between regions with live preview. Click any block in the preview to edit inline. Mobile, tablet, and desktop preview modes.
Hierarchical Menus
Deep-nesting support, multiple independent menus, container items, and helper functions for navigation, breadcrumbs, and active states.
REST + GraphQL APIs
Structured REST API with batch fetching, ETag caching, and rate limiting. Plus a full GraphQL API for complex queries in a single request.
Multi-Language (i18n)
Page-level localization with linked translations, locale-scoped slugs, and language switcher support. Configure supported locales in settings.
OAuth + 2FA Security
Google, GitHub, and Microsoft OAuth login. TOTP two-factor authentication with recovery codes and trusted devices. Role-based access control.
AI Content Helpers
Connect OpenAI, Anthropic, Google Gemini, or run local models with Ollama. AI-powered meta descriptions, alt text suggestions, and content drafting.
Custom Workflows
Configurable content stages with role-based transitions. Draft to In Review to Approved to Published — define any workflow your team needs.
Full-Text Search
SQLite FTS5 with Porter stemming searches page titles, content, and metadata. BM25 relevance ranking and prefix matching.
Deploy Anywhere
Docker, Cloudflare Workers, bare Node.js. SQLite or PostgreSQL. 5 starter templates for blog, marketing, WordPress, Drupal, and college sites.
Custom Content Types
Define your own content types with custom fields, regions, and block restrictions. Match any content model your site needs.
Lifecycle Hooks
Run custom code before or after content operations. Validate data, block publishing, sync to external services — the foundation for a plugin system.
Dark Mode Admin
Light, dark, and system theme modes. Mobile-responsive with hamburger sidebar. Loading skeletons, keyboard shortcuts, and Cmd+K search.
Developer Experience
Fetch content in 3 lines
The @wollycms/astro package gives you a typed client, component rendering, menu helpers, SEO utilities, and responsive images out of the box.
- Full TypeScript types — no casting, no guessing
- BlockRenderer maps CMS blocks to your Astro components
- Menu helpers for nav, breadcrumbs, and active states
- WollyImage component with responsive srcset and lazy loading
class="text-slate-500">---
class=class="text-amber-400">"text-sky-400">import class="text-slate-300">{ wolly } class=class="text-amber-400">"text-sky-400">from class="text-amber-400">'../lib/wolly';
class=class="text-amber-400">"text-sky-400">import * as blocks class=class="text-amber-400">"text-sky-400">from class="text-amber-400">'../lib/blocks';
class=class="text-amber-400">"text-sky-400">import class="text-slate-300">{ BlockRenderer } class=class="text-amber-400">"text-sky-400">from class="text-amber-400">'@wollycms/astro';
class=class="text-amber-400">"text-sky-400">import Layout class=class="text-amber-400">"text-sky-400">from class="text-amber-400">'../layouts/Default.astro';
class=class="text-amber-400">"text-sky-400">const slug = Astro.params.slug || class="text-amber-400">'home';
class=class="text-amber-400">"text-sky-400">const page = class=class="text-amber-400">"text-sky-400">await wolly.pages.getBySlug(slug);
class=class="text-amber-400">"text-sky-400">const menu = class=class="text-amber-400">"text-sky-400">await wolly.menus.get(class="text-amber-400">'main');
class="text-slate-500">---
class="text-sky-400"><Layout title=class="text-slate-300">{page.title} menu=class="text-slate-300">{menu}>
class="text-sky-400"><BlockRenderer
blocks=class="text-slate-300">{page.regions.hero}
components=class="text-slate-300">{blocks}
/>
class="text-sky-400"><BlockRenderer
blocks=class="text-slate-300">{page.regions.content}
components=class="text-slate-300">{blocks}
/>
class="text-sky-400"></Layout> Infinite Page Types
Define any content model
Blog posts, landing pages, product pages, case studies — define the page type, assign regions and blocks, and WollyCMS handles the rest. Every page type gets its own fields, regions, and block restrictions.
- Custom fields per page type — dates, tags, authors, anything
- Named regions — hero, sidebar, content, footer — you decide
- Block restrictions per region control what editors can use
- Full taxonomy system for categories, tags, and custom vocabularies
class="text-slate-500">// Register page types in WollyCMS admin
class=class="text-amber-400">"text-sky-400">const blogPost = {
type: class="text-amber-400">"blog_post",
fields: [
{ name: class="text-amber-400">"author", type: class="text-amber-400">"text" },
{ name: class="text-amber-400">"date", type: class="text-amber-400">"date" },
{ name: class="text-amber-400">"tags", type: class="text-amber-400">"taxonomy", vocab: class="text-amber-400">"tags" }
],
regions: {
hero: { allowed: [class="text-amber-400">"hero"] },
content: { allowed: [class="text-amber-400">"rich_text", class="text-amber-400">"image", class="text-amber-400">"code_example"] },
sidebar: { allowed: [class="text-amber-400">"author_card", class="text-amber-400">"related_posts"] }
}
}
class="text-slate-500">// Fetch typed content in Astro
class=class="text-amber-400">"text-sky-400">const post = class=class="text-amber-400">"text-sky-400">await wolly.pages.getBySlug(class="text-amber-400">"my-post");
class="text-slate-500">// post.fields.author -> class="text-amber-400">"Chad"
class="text-slate-500">// post.regions.hero -> [{ block_type: class="text-amber-400">"hero", ... }]
class="text-slate-500">// post.regions.sidebar -> [{ block_type: class="text-amber-400">"author_card", ... }] Hierarchical Menus
Navigation that just works
Build unlimited independent menus with deep nesting, container items, and external links. The @wollycms/astro package gives you helpers for nav rendering, breadcrumbs, and active-state detection.
- Multiple independent menus — main nav, footer, sidebar, mobile
- Deep nesting with parent/child relationships
- Container items for mega-menu style dropdowns
- Active state and breadcrumb helpers out of the box
class="text-slate-500">---
class=class="text-amber-400">"text-sky-400">import class="text-slate-300">{ getWolly } class=class="text-amber-400">"text-sky-400">from class="text-amber-400">"../lib/wolly";
class=class="text-amber-400">"text-sky-400">const wolly = getWolly();
class="text-slate-500">// Fetch any menu by name
class=class="text-amber-400">"text-sky-400">const main = class=class="text-amber-400">"text-sky-400">await wolly.menus.get(class="text-amber-400">"main");
class=class="text-amber-400">"text-sky-400">const footer = class=class="text-amber-400">"text-sky-400">await wolly.menus.get(class="text-amber-400">"footer");
class="text-slate-500">---
<nav>
class="text-slate-300">{main.items.map((item) => (
<a href={item.url} class:list={[
class="text-amber-400">"nav-link",
{ active: Astro.url.pathname === item.url }
]}>
class="text-slate-300">{item.label}
{item.children?.length > 0 && (
<ul class=class="text-amber-400">"dropdown">
{item.children.map((child) => (
<li><a href={child.url}>class="text-slate-300">{child.label}</a></li>
))}
</ul>
)}
</a>
))}
</nav> Comparison
The features that set WollyCMS apart
Drupal's content model power, modern developer experience, no vendor lock-in.
| Feature | WollyCMS | Strapi | Payload | Storyblok | Keystatic |
|---|---|---|---|---|---|
| Block composition with regions | — | — | — | ||
| Reusable block instances | — | — | — | — | |
| Hierarchical menus built-in | — | — | — | — | |
| Visual page builder | — | — | — | ||
| Astro integration package | — | — | |||
| Self-hosted | — | ||||
| Open source (MIT) | — | ||||
| OG image auto-generation | — | — | — | — | |
| Deploy anywhere (Docker/Workers/Node) | — |