Build lightning-fast websites with the editing experience your content team actually wants to use.
A production-ready template combining ApostropheCMS as a headless backend with Astro as a modern frontend framework. This template includes a beautiful design system and rich content features, all completely free and open source.
- 🚀 Headless CMS with Frontend Integration - Full ApostropheCMS Admin UI with in-context editing
- ⚡ Modern Frontend - Astro for optimal performance and developer experience
- 🎨 Production Styled - Beautiful Bulma-based design system included
- 📱 Fully Responsive - Mobile-first approach with modern web standards
- 💰 Completely Free - No license fees, perfect for any project size
Choose the right foundation for your project:
Perfect if you want: A production-ready foundation with beautiful design included
- Production-Ready Design: Complete Bulma-based design system with modern styling
- Rich Feature Set: Advanced widgets, layouts, and pre-styled components
- Faster Time-to-Market: Launch professional sites with minimal additional styling
- Content-Rich Sites: Built-in blog, author relationships, and content management features
- Best for: Teams who want to focus on content and functionality over design from scratch
Perfect if you want: A clean, minimal foundation to build your own design system
- Minimal & Non-opinionated: Essential building blocks without imposed design decisions
- Core Components: Basic page types, essential widgets, and clean architecture
- Maximum Flexibility: Build your own styling approach and component library
- Learning Focus: Understand the ApostropheCMS + Astro integration from the ground up
- Best for: Developers who want full creative control and custom design systems
Ready for enterprise features? Upgrade to Apollo Pro for advanced permissions, automated translations, SEO optimization, document versioning, and more professional capabilities.
- Apollo Starter Kit for ApostropheCMS + Astro Integration
- ✨ What Makes This Special
- ApostropheCMS + Astro Starter Kits
- 🌟 Apollo Starter Kit (This Repository)
- 🎯 Astro Essentials Starter Kit
- Table of Contents
- Introduction
- 🚀 Getting Started
- 🏗️ Project Architecture
- 🌟 Features & Widgets
- 🖼️ Image Helper Functions
- 🖌️ Theming
- ⚙️ Package scripts
- 🚀 Deploying to production
- 💎 Ready for More?
- 🚑 Need Help?
- 📚 Learn More
- License
Overall, this project utilizes ApostropheCMS as a headless backend with Astro as a frontend. What sets this apart from the typical headless use of ApostropheCMS is the addition of a package, apostrophe-astro in the Astro frontend project. This allows for full use of the ApostropheCMS Admin UI, including in-context editing. At the same time, this package also largely automates and simplifies fetching content from the ApostropheCMS backend without writing REST API calls into your code.
Required:
- Node.js v20 or later (v22 recommended)
- MongoDB v6.0 or later (local server or Atlas). See the ApostropheCMS documentation for setup.
Windows Users:
- Windows Subsystem for Linux 2 (WSL2) required for Apostrophe development. This ensures consistent behavior with image processing tools and file system operations. Learn more about setting up WSL2 from Microsoft and in our documentation.
The codebases located in the backend
and frontend
folders should be treated as interlinked but separate projects.
To simplify dependency management, this repository includes several root-level scripts for convenience. The postinstall
script automatically installs dependencies for both the frontend
and backend
folders when you run npm install
at the root.
-
Install dependencies
npm install
-
Load starter content (optional, but recommended)
npm run load-starter-content
This fetches a starter database and media files. You'll be prompted to set an admin password.
-
Start development servers Open two terminals:
- Mac/Linux users: One terminal in
frontend
folder, one inbackend
folder - Windows users: WSL terminal for
backend
folder, WSL or Windows terminal forfrontend
folder
# Terminal 1 - Backend (use WSL on Windows) cd backend && npm run dev # Terminal 2 - Frontend cd frontend && npm run dev
That's it! The
npm run dev
scripts automatically handle authentication between the frontend and backend in development mode setting theAPOS_EXTERNAL_FRONT_KEY
to "dev". For production or when you are starting your frontend or backend with a different command you will have to set this environment variable to the same value for both.Optional: If running the backend on a different server/port, set the frontend's backend URL:
# In the frontend terminal only export APOS_HOST=your-backend-url
- Mac/Linux users: One terminal in
Your site will be available at http://localhost:4321
(Astro frontend). The ApostropheCMS backend will be available at http://localhost:3000
, but it just gives notification of whether it is connected to the Astro frontend. In most cases you never need to access this page.
Note: Astro is less stringent about project setup in development mode. Before deployment, run
npm run build
followed bynpm run preview
in thefrontend
folder to test production behavior. We don't recommend using the rootnpm run serve-frontend
script during development - it's used for ApostropheCMS hosting.
cd backend
node app @apostrophecms/user:add admin admin
This creates a user named admin
with the correct privileges. You will be asked to enter a password.
This project utilizes ApostropheCMS as a headless backend with Astro as a frontend. What sets this apart from typical headless setups is the apostrophe-astro package in the Astro frontend project. This enables full use of the ApostropheCMS Admin UI, including in-context editing, while largely automating content fetching from the backend without writing REST API calls.
├── backend/ # ApostropheCMS application
│ ├── modules/ # Custom modules (pages, pieces, widgets)
│ ├── app.js # Main configuration
│ ├── package.json # ApostropheCMS-specific scripts
│ └── ...
├── frontend/ # Astro application
│ ├── src/
│ │ ├── pages/ # Single [...slug].astro route
│ │ ├── templates/ # Page templates
│ │ ├── widgets/ # Widget templates
│ │ └── components/ # Astro components
│ ├── astro.config.mjs # Astro configuration
│ ├── package.json # Astro-specific scripts
│ └── ...
└── README.md # This file
└── package.json. # Whole project scripts
If you've worked with ApostropheCMS previously, the backend should look familiar. Custom modules for pages, pieces, and widgets are in the modules
folder, with core module configuration in modules/@apostrophecms
.
What stays the same:
- Module registration in
app.js
- Page types added to
modules/@apostrophecms/page/index.js
- Most module configuration settings for Admin UI, request routing, and MongoDB interaction
Key differences:
- No frontend code in modules - Stylesheets, templates (implemented as Astro components), and client-side JavaScript go in the Astro project instead
- No template helpers - Skip
helper()
,extendHelpers()
,components()
, andrenderRoutes()
functions - Schema sharing - Some widget schemas have been moved to
lib/schema-mixins
for reuse between widgets and pages
The modules/@apostrophecms/home-page
module loads the core views/layout.html
file, which has been modified to show project status information instead of the Admin UI.
The Astro portion follows standard conventions with components in src
and assets in public
. Configuration is managed through astro.config.mjs
following standard practices.
What stays the same:
- Standard Astro project organization
- Normal component and template patterns
- Client-side asset management
Key differences:
- Single route system - Instead of multiple routes in
pages
, there's one[...slug].astro
file that handles all routing - Template mapping - Pages map to templates in the
templates
folder, mapped by theindex.js
file in that folder. Each template corresponds to an ApostropheCMS page type, includingindex.html
andshow.html
piece-page types - Widget system - The
widgets
folder contains templates for ApostropheCMS widgets, mapped through anindex.js
file in that folder. - Required configuration - The
apostrophe
integration andoutput: 'server'
settings must remain for backend integration
Unlike typical Astro projects with multiple route files, this project uses a single [...slug].astro
route that:
- Handles all URL routing using pages from the CMS backend
- Maps page types to corresponding templates in the
templates
folder - Populates template content with data from the CMS
- Renders widgets using templates from the
widgets
folder
Each page template corresponds to a registered ApostropheCMS page or piece-page type. Content is populated by data from the CMS backend and inserted into slots in the main [...slug].astro
file. Widget data is handled through the mapped templates and added to page templates using the AposArea
helper component.
Read more in the apostrophe-astro
documentation or in the Apollo tutorial series.
This architecture allows widget templates to be used outside specialized area
schema fields, providing design flexibility without code repetition. However, this means widget schema fields for content must also be added to page schemas. The backend/lib/schema-mixins
folder facilitates this by allowing schema imports in both widget modules and page templates.
The astro.config.mjs
includes required settings for ApostropheCMS integration:
apostrophe
integration in the integrations arrayoutput: 'server'
for server-side rendering- Custom preprocessor options (this project uses a different SASS compiler for Bulma CSS framework compatibility)
Read more in the apostrophe-astro
documentation.
This project is more opinionated than some of our other project starter kits. It uses the Bulma CSS framework. For a more streamlined starting point you can use the Astro Essentials starter kit repository.
This project provides the core ApostropheCMS widgets, plus seven additional widgets:
- Layout
- rows-widget: adds rows with varying numbers of columns for responsive content layout
- grid-layout-widget: adds custom or predefined CSS grid-based layouts
- Content
- hero-widget: a customizable hero section with options for color gradient, image, or video backgrounds
- slideshow-widget: a customizable slideshow widget
- accordion-widget: adds an accordion for organizing content into collapsible sections
- card-widget: allows for the creation of multiple different customizable card-types
- link-widget: adds links that can be styled as text or a highly customizable button
This project creates two pieces. The first is an article
piece for the creation of content pieces like blog posts or news articles. The second is an author
piece that is used in relationship with the article pieces.
This project creates core default
and @apostrophecms/home-page
pages. It also creates two pages for displaying the article pieces.
The home-page has three potential layouts selected from the utility menus on the right-side of the page manager. The 'Minimal' layout inherits the header and footer components that is added to all the project pages. It also has a single area that can take any of the project widgets. The 'Foundation' layout adds a hero section at the top of the page, while the 'Showcase' adds a slideshow.
The default page has a layout that is identical to the 'Minimal' home-page layout.
Piece-type pages in ApostropheCMS only projects are used to either display multiple pieces (index.html
) or individual pieces (show.html
). This project has both types of pages, mapping the index of all pieces to the ArticleIndexPage.astro
template and the display of the individual pieces to the ArticleShowPage.astro
template. Both of these page types have three layouts for you to select from. Depending on the index layout, there are three or four additional areas for adding widgets with content before and after the piece content. The index page also demonstrates how to handle pagination in a hybrid project.
These helper functions are designed to work with images in your Astro frontend that come from ApostropheCMS through relationships or attachment fields. If you're using the image widget within an area, you should use the AposArea
helper instead - these utilities are specifically for handling images that are part of your content model.
Important: These helpers expect a single attachment object, not an array. When working with relationships or array fields, make sure to pass a single image object (e.g., page.relationship._image[0]
) rather than the full array.
When you have a relationship field to @apostrophecms/image
in your content type, you'll typically need to:
- Get the image URL (potentially at different sizes for responsive images)
- Handle focal points if configured
- Get the image dimensions including any cropping that should be applied
- Set up proper alt text
Here's a typical example:
---
import {
getAttachmentUrl,
getAttachmentSrcset,
getFocalPoint,
getWidth,
getHeight
} from '../lib/attachments.js';
// Get first image from relationship
const image = relationshipField._image[0];
---
<img
src={getAttachmentUrl(image, { size: 'full' })}
srcset={getAttachmentSrcset(image)}
sizes="(max-width: 800px) 100vw, 800px"
alt={image.alt || image.title || 'Image description'}
width={getWidth(image)}
height={getHeight(image)}
style={`object-position: ${getFocalPoint(image)};`}
/>
For attachment fields (like logo fields), the pattern is similar:
<img
src={getAttachmentUrl(attachmentField)}
width={getWidth(attachmentField)}
height={getHeight(attachmentField)}
alt="Logo"
/>
Automatic Crop Handling
If you set a crop region for an image in the ApostropheCMS Admin UI, all the helper methods will automatically respect that crop. You don't need to do anything special in your code - the cropped version will be used when generating URLs and srcsets.
Size Variants
The default size variants are:
one-sixth
(190×350px)one-third
(380×700px)one-half
(570×700px)two-thirds
(760×760px)full
(1140×1140px)max
(1600×1600px)
These sizes will be used to generate the srcset and can be selected by name for the getAttachmentUrl()
method:
getAttachmentUrl(image, { size: 'full' })
You can use custom size names in both getAttachmentUrl()
and the srcset options. For example:
const customUrl = getAttachmentUrl(image, { size: 'custom-banner' });
// Custom srcset configuration
const srcset = getAttachmentSrcset(image, {
sizes: [
{ name: 'small', width: 300 },
{ name: 'medium', width: 600 },
{ name: 'large', width: 900 },
]
});
Important: These helpers don't generate the image sizes - they just reference sizes that already exist. To use custom sizes, you must configure the
@apostrophecms/attachment
module to create those sizes when images are uploaded. You can do this in your backend configuration:
// modules/@apostrophecms/attachment/index.js
module.exports = {
options: {
// Define what sizes should be created on upload
imageSizes: {
'custom-banner': { width: 1200, height: 400 },
'square-thumb': { width: 300, height: 300 },
'small': { width: 300 },
'medium': { width: 600 },
'large': { width: 900 }
}
}
};
See the attachment module documentation for complete configuration options.
When using focal points set in the ApostropheCMS admin UI, you'll need to:
- Use
object-position
with the focal point value - Set appropriate Bulma image classes (like
is-fullwidth
)
<figure class="image">
<img
src={getAttachmentUrl(image)}
style={`object-position: ${getFocalPoint(image)}; object-fit: cover;`}
class="is-fullwidth"
width={getWidth(image)}
height={getHeight(image)}
alt="Image with focal point"
/>
</figure>
The getFocalPoint()
function returns coordinates in the format "X% Y%" (e.g., "50% 50%" for center). If no focal point is set, it returns the default value (default is "center center").
Key functions available (see JSDoc comments in source for detailed documentation):
getAttachmentUrl(attachmentObject, options?)
: Get URL for an image with optional size (defaults to 'full')getAttachmentSrcset(attachmentObject, options?)
: Generate responsive srcset stringgetWidth(imageObject)
: Get image width, respecting cropsgetHeight(imageObject)
: Get image height, respecting cropsgetFocalPoint(attachmentObject, defaultValue?)
: Get focal point coordinates for styling
Customizing the theme in this project is straightforward and leverages Bulma's powerful theming capabilities. You can override Bulma's default variables to match your brand or design requirements by editing the frontend/src/styles/main.scss
file. This is done before importing Bulma so that your customizations are applied throughout the project.
- Navigate to the
frontend/src/styles/main.scss
file. - Locate the section for overriding Bulma variables.
- Uncomment and modify the variables you wish to customize. You can define colors, typography, spacing, and more.
- Save your changes, and the updated theme will automatically apply when you rebuild the project.
Here's an example of how to customize some of Bulma's common variables. These variables are commented out by default. Uncomment and modify them as needed:
@use 'bulma/sass/utilities/initial-variables' as * with (
// Colors
$turquoise: hsl(171, 100%, 41%), // Primary color
$cyan: hsl(204, 86%, 53%), // Info color
$green: hsl(141, 71%, 48%), // Success color
$yellow: hsl(48, 100%, 67%), // Warning color
$red: hsl(348, 100%, 61%), // Danger color
// Typography
$family-sans-serif: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif,
$family-monospace: monospace,
$size-1: 3rem,
$size-2: 2.5rem,
$size-3: 2rem,
$size-4: 1.5rem,
$size-5: 1.25rem,
$size-6: 1rem
);
For a comprehensive list of all customizable variables, refer to the Bulma documentation on variables. This resource provides details on all available options for customization, including advanced options for responsive breakpoints, spacing, and more.
- Order matters: Ensure your variable overrides are declared before importing Bulma to avoid conflicts.
- SASS compatibility: This setup uses the modern SASS syntax with @use and @forward. If you are unfamiliar with these concepts, refer to the SASS documentation for more information.
- Theme consistency: To maintain a cohesive design, consider defining your core color palette and typography styles at the beginning of your project.
If your changes are not reflected:
- Ensure your variables are correctly uncommented and modified.
- Check for any caching issues by clearing your browser cache or restarting the build process.
The root of the project has several useful scripts located in the package.json
file. Running npm run install
in the root directory will trigger the postinstall
script. This will install the dependencies for both the ApostropheCMS and Astro projects. Similarly, npm run update
will update dependencies for both the frontend
and backend
folders. The rest of the scripts in this file are primarily used for project deployment to ApostropheCMS hosting.
The main scripts for the Astro project located in the frontend folder are dev
, preview
, and build
. These first two of these scripts will allow you to start the Astro server in either development or preview mode. The build
script should be run prior to starting the server in preview mode. The remainder of the scripts are for deployment and may need to be altered to fit your hosting solution.
Typically, you will only use the dev
script in the backend folder outside of deployment. You can consult the ApostropheCMS hosting recipes to see how these other scripts should be used.
ApostropheCMS can provide easy hosting for any ApostropheCMS-Astro monorepo with little or no extra configuration. This can be set up for deployment from Github or other code repository.
ApostropheCMS hosting will automatically handle:
- Database provisioning and management
- Asset storage and delivery
- SSL certificate management
- Automatic backups
- Security updates
In the future, we will be providing a path to create your own account and create a new hosted project. In the meantime, you can learn more and contact us to get your hosting set up.
Third-party hosting will typically require separate servers for the ApostropheCMS and Astro portions of the repositories. This is the typical pattern seen with other CMS that are used with Astro. You will need to specify whether you want the backend
ApostropheCMS portion of the repo, or the frontend
Astro project hosted. How this is accomplished will depend on the provider.
Your ApostropheCMS backend requires:
- Node.js environment (v20 or later recommended)
- MongoDB database
- Asset storage solution (cloud storage like AWS S3)
There are several examples of common deployment strategies in our documentation
Example deployment steps for a typical provider:
- Set up a MongoDB instance (Atlas, DigitalOcean, etc.)
- Configure your server with Node.js and PM2
- Set up your environment variables:
NODE_ENV=production APOS_MONGODB_URI=YOUR_mongodb_connection_string APOS_EXTERNAL_FRONT_KEY=a_random_string APOS_S3_BUCKET=YOUR-bucket-name APOS_S3_SECRET=YOUR-s3-secret APOS_S3_KEY=YOUR-s3-key APOS_S3_REGION=YOUR-chosen-region
The remainder of the deployment will depend on the hosting platform being used and how that deployment is triggered. Generally, it will comprise a build step followed by bringing up the server. If you are not deploying with Git, you will also need to set the APOS_RELEASE_ID
to a unique, random value. Again, make sure that you specify that the backend
folder is to be used as the root for your deployment.
Your Astro frontend can be deployed to any static hosting provider that supports SSR (Server-Side Rendering). Popular options include:
- Netlify
- Vercel
- Cloudflare Pages
- AWS Amplify
There are a number of tutorials in the Astro documentation to use as a starting point. The only modifications are the extra environment variable,
APOS_EXTERNAL_FRONT_KEY=a_random_string
set to the same string as your backend project, and to make sure that you are specifying thefrontend
folder as the root of the project.
- Log in to your Netlify account.
- Create a new site by connecting your Git repository.
- In the "Build settings" configuration:
- Base directory:
frontend
- Build command:
npm run build
- Publish directory:
frontend/dist
- Base directory:
- Access Site Settings: -Navigate to the "Site settings" for the selected site.
- Scroll down and find the "Environment variables" section under the "Build & deploy" tab. Click "Edit variables". Add a New Variable:
- Key:
APOS_EXTERNAL_FRONT_KEY
- Value:
a_random_string
- Key:
- Save your configuration and deploy the site.
The build settings can also be supplied through a netlify.toml
file at the root of your project.
Love what you see but need enterprise features? This free Apollo starter kit is just the beginning. Upgrade to Apollo Pro to unlock powerful capabilities that will supercharge your content management and development workflow:
- 🔐 Advanced Permissions - Granular access control and user groups for teams
- 🌍 Automated Translation - AI-powered translation with DeepL, Google Translate, and Azure
- 🎨 Visual Design Tools - In-context CSS customization with the Palette extension
- 🔍 SEO Optimization - AI-powered content optimization for better search rankings
- 📝 Document Management - Version control, templates, and audit trails
- 👥 User Registration - Self-service signup and account management
Contact our team to learn more about Apollo Pro licensing and get access to enterprise-grade features that will accelerate your development and enhance your content management capabilities.
- Documentation: Each feature includes comprehensive documentation and examples
- Community Support: Join our Discord community for help from other developers
- Professional Support: Dedicated support packages available - Contact us to learn more
- Training: Professional training and consultation services available
- ApostropheCMS Documentation - Complete CMS guide
- Astro Documentation - Learn more about Astro
- Astro + ApostropheCMS Guide - Integration details
- Building a Site Tutorial - Building a complete site with the Apollo theme
- apostrophe-astro Package - Bridge package docs
This project is licensed under the MIT License. See the LICENSE file for details.
Built with ❤️ by the ApostropheCMS team. Star us on GitHub if this helps your project!