Building an Astro website is straightforward until content, editorial workflows, media, and public delivery all need to work together. Beaver brings those pieces into one package: a CMS admin panel and middleware for Astro SSR projects.
Beaver is designed for teams that want a working content system without turning every public page into a custom integration. Content lives in the CMS, while the website remains a file-based Astro project that developers can shape around the product.
What Beaver provides
The admin panel supports pages and posts with draft and published states, publication dates, slugs, excerpts, descriptions, tags, categories, featured images, galleries, and SEO metadata. Editors can work with rich text, duplicate content, publish or unpublish items in bulk, and remove multiple records when needed.
The content model is not limited to posts. Beaver uses registries for custom content types, archive layouts, detail layouts, page sections, and menus. That makes it possible to add a case-study or resource library while keeping the same CMS workflow.
Media is part of the same workflow. The media library stores files with folders, captions, alternative text, metadata, thumbnails, and responsive image variants. Upload validation checks the file signature, MIME type, size, image dimensions, and pixel count. Local storage and Amazon S3 are both supported.
For sites that need to receive messages, Beaver also includes a public inquiry form. The form can use SMTP delivery, reply-to addresses, Turnstile verification, input validation, and rate limiting.
Start a project in one command
The interactive initializer creates a new Beaver project:
npm create @zbeaver/beaver
The wizard asks for the project name, starter template, package manager, and Super Admin details. It then creates the Astro project, installs dependencies, generates the configuration, runs the database migration, seeds Beaver and the selected template, and prints the website and admin URLs.
Beaver supports SQLite, MySQL, and PostgreSQL through Drizzle migrations. SQLite is a convenient default for local development and smaller deployments, while MySQL and PostgreSQL are available when the application needs a separate database service.
A small project root, a flexible src/ directory
The initializer keeps the main project configuration familiar:
project/
├── .env
├── astro.config.mjs
└── src/
The .env file contains server-side settings for the database, authentication, storage, email, and cache. Important values include DB_CONNECTION, DB_DATABASE, the admin credentials, session and JWT secrets, ADMIN_PATH, and the storage configuration.
For local files, configure a path such as:
STORAGE_TYPE=local
STORAGE_PATH=./public/storage
For S3, set the region, bucket, and credentials instead. Both storage backends use the same public /storage/<file> URL format, so changing the backend does not require changing the website components.
The public website is built directly in src/. Layouts provide the shared HTML shell, pages define routes, components render reusable UI, and styles hold the public design tokens and base rules. Astro SSR, React islands, and Tailwind can be used together.
Registries keep the website adaptable
Beaver does not require developers to hard-code every content route. A content-type registry connects a content type to its archive and detail templates. For example, a case-study type can use its own grid and reader components:
src/components/web/content-type-templates/archive/case-study-grid.astro
src/components/web/content-type-templates/detail/case-study-reader.astro
The matching template IDs live in src/components/web/content-type-templates/registry.json. The public archive and detail routes read those IDs and resolve the corresponding Astro components automatically.
Page sections follow the same idea. A section registry describes the available section type, its editable fields, and its item mode. Sections can be single-item or repeatable, and can load published content such as posts. The template includes common sections for heroes, contact forms, FAQs, videos, maps, pricing, showcases, steps, testimonials, banners, and post collections.
Menus are registry-based too. Navbar, footer, and sidebar groups are defined in the menu registry, while the actual links remain editable CMS data. This keeps navigation content separate from the layout that renders it.
Render CMS content in Astro
Astro pages, layouts, and components can use the server-side helpers from @zbeaver/beaver/server. These helpers return published content for the website, so draft and private records are not exposed to unauthenticated visitors.
To load one published page or post:
---
import { getPublishedPostByType, sanitizeHtml } from "@zbeaver/beaver/server"
const result = getPublishedPostByType("post", Astro.params.slug || "")
if (!result.success) return new Response("Post not found", { status: 404 })
const post = result.data
---
<article>
<h1>{post.title}</h1>
{post.description && <div set:html={sanitizeHtml(post.description)} />}
</article>
For archives, listPublishedPostsByType supports pagination and filters for search, categories, tags, custom fields, title, and creation date. Dedicated helpers are also available for search, tag archives, menus, and site settings.
Rich-text content should be sanitized before it is rendered. Beaver provides sanitizeHtml for that purpose, and the generated middleware adds security headers, content security policy rules, request-size protection, download handling, and no-cache behavior for admin routes.
CLI commands for ongoing work
After the first setup, the Beaver CLI covers common maintenance tasks:
# Apply pending migrations
npx @zbeaver/beaver migrate
# Validate seed data without writing to the database
npx @zbeaver/beaver migrate:data ./data/seed.json --dry-run
# Seed the system and the Flowstack demo template
npx @zbeaver/beaver seed flowstack
# Reset the Super Admin password from .env
npx @zbeaver/beaver reset superadmin
Seed data uses a portable JSON shape with settings, categories, posts, pages, and menus. Existing records are skipped by default, and --overwrite can update records that match an existing slug or menu identity.
A useful boundary between code and content
Beaver's main strength is the boundary it creates. Editors manage content, metadata, media, and navigation from the admin panel. Developers control the Astro templates, registries, sections, routes, and styles in source control. Server-side helpers connect the two without forcing the website into a fixed visual structure.
That approach works well for an Astro project that needs a CMS but still wants the speed and control of a code-owned frontend. Start with the generated Flowstack template, replace its public components with the site's own design, and add custom content types only when the content model calls for them.
For the complete configuration reference and server-side helper details, see the Beaver package.

Top comments (0)