SDK: Astro Example
Introduction & Overview#
This project demonstrates how to build dynamic, fully editable pages using dotCMS as a headless CMS with a Astro front end. By combining these technologies, you can:
- Create content in dotCMS and deliver it headlessly to your Astro application
- Edit content visually using dotCMS's Universal Visual Editor (UVE) directly on your Astro front end
- Build high-performance pages leveraging Astro's server-side rendering capabilities
- Maintain content separation between your CMS and presentation layer
How It Works#
┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │ │ │ │ │ │ dotCMS │──────▶ Astro │──────▶ Browser │ │ (Content) │ │ (Front end) │ │ (Viewing) │ │ │ │ │ │ │ └───────────────┘ └───────────────┘ └───────────────┘ ▲ │ │ │ │ │ └──────────────────────┴──────────────────────┘ Universal Visual Editor (UVE) (Content Editing)
The integration uses dotCMS APIs to fetch content and the Universal Visual Editor to enable in-context editing directly on your Astro pages.
Demo#
See a live example at https://astro-example-sigma-five.vercel.app/.
The example above is a Astro front end for the dotCMS demo site, and changes to pages and content on the latter will be reflected, there. For more information on the demo site, see the relevant section below.
Prerequisites#
Before you begin, make sure you have:
System Requirements#
- Node.js: v18.20.8 (LTS) or later (v22+ recommended)
- NPM, Yarn, or pnpm package manager
- Git for version control
- A code editor (VS Code, WebStorm, etc.)
dotCMS Requirements#
- dotCMS instance: Access to a dotCMS instance (v25.05 or Evergreen recommended)
- For testing: You can use the dotCMS demo site
- For production: Sign up for a dotCMS instance
- Administrator access: To create API tokens and configure the Universal Visual Editor
- API token: With appropriate read permissions for your Astro app
Knowledge Prerequisites#
- Basic understanding of React and Astro concepts
- Familiarity with content management systems (prior dotCMS experience helpful but not required)
dotCMS SDK Dependencies#
[!NOTE] These packages are already included in the example project's dependencies, so you don't need to install them separately.
This example uses the following npm packages from dotCMS:
Package | Purpose | Description |
---|---|---|
@dotcms/client | API Communication | Core API client for fetching content from dotCMS |
@dotcms/react | UI Components | React components and hooks for rendering dotCMS content |
@dotcms/uve | Visual Editing | Universal Visual Editor integration |
@dotcms/types | Type Safety | TypeScript type definitions for dotCMS |
Setup Guide#
This guide will walk you through the process of setting up the dotCMS Astro example from scratch.
Step 1: Create the Astro Application#
Use one of the following commands to create a new Astro app with the dotCMS example:
# Using npm npm create astro@latest -- --template https://github.com/dotCMS/core/tree/main/examples/astro
This will create a new directory with the example code and install all necessary dependencies.
Step 2: Configure dotCMS Access#
A. Get a dotCMS Site#
First, get a dotCMS Site. If you want to test this example, you can also use our demo site.
If using the demo site, you can log in with these credentials:
User Name | Password |
---|---|
admin@dotcms.com | admin |
Once you have a site, you can log in with the credentials and start creating content.
B. Create a dotCMS API Key#
[!TIP] Make your API Token had read-only permissions for Pages, Folders, Assets, and Content. Using a key with minimal permissions follows security best practices.
This integration requires an API Key with read-only permissions for security best practices:
- Go to the dotCMS admin panel.
- Click on System > Users.
- Select the user you want to create the API Key for.
- Go to API Access Key and generate a new key.
For detailed instructions, please refer to the dotCMS API Documentation - Read-only token.
C. Configure the Universal Visual Editor#
The Universal Visual Editor (UVE) is a critical feature that creates a bridge between your dotCMS instance and your Astro application. This integration Enables real-time visual editing and allows content editors to see and modify your actual Astro pages directly from within dotCMS.
To set up the Universal Visual Editor:
- Browse to Settings > Apps.
- Select the built-in integration for UVE - Universal Visual Editor.
- Select the site that will be feeding the destination pages.
- Add the following configuration:
{ "config":[ { "pattern":"(.*)", "url":"http://localhost:3000" } ] }
For detailed instructions, see the dotCMS UVE Headless Configuration.
This configuration tells dotCMS that when editors are working on content in the admin panel, they should see your Astro application running at http://localhost:3000
. The pattern (.*)
means this applies to all pages in your site.
Step 3: Configure the Astro Application#
A. Set Environment Variables#
Create a .env.local
file in the root of the project by running the following command:
# This will create a new file with the correct variables. cp .env.local.example .env.local
Then set each variable in the .env.local
file:
NEXT_PUBLIC_DOTCMS_HOST
: The URL of your dotCMS site.NEXT_PUBLIC_DOTCMS_AUTH_TOKEN
: The API Key you created in Step 2B.NEXT_PUBLIC_DOTCMS_SITE_ID
: The site key of the site you want to use.
The site ID variable refers to the site that will be used to pull content into your Astro app. dotCMS is a multi-site CMS, meaning a single instance can manage multiple websites; the site ID specifies which site's content should be pulled into your Astro app. If left empty or given an incorrect value, content will be pulled from the default site configured in dotCMS.
You can find the values for this variable — site keys or identifiers both work, though keys are simpler and more recommended — under System > Sites. Learn more about dotCMS Multi-Site management here.
Step 4: Run the Application#
Run the development server with one of the following commands:
# Using npm npm run dev # Using Yarn yarn dev # Using pnpm pnpm dev
You should see a message in your terminal indicating that the Astro app is running at http://localhost:3000
. Open this URL in your browser to see your dotCMS-powered Astro site.
Edit your page in the Universal Visual Editor#
After setting up the Universal Visual Editor and running your Astro application, you can edit your page in the Universal Visual Editor:
- Log in to the dotCMS admin panel
- Browse to Site > Pages
- Open the page you want to edit
- The page will be rendered in the editor with your Astro front end
- Make changes directly on the page
Learn more about the Universal Visual Editor here.
Advanced: Astro + dotCMS Architecture#
Integration Overview#
The integration between dotCMS and Astro works by:
- Content Creation: Content editors create and manage content in dotCMS
- Content Delivery: Astro fetches content from dotCMS using the API client
- Content Rendering: React components render the fetched content
- Visual Editing: The Universal Visual Editor enables in-context editing
File Structure#
src/ ├── pages/ # Astro file-based routing │ ├── blog/ │ │ ├── index.astro # Renders the main blog listing page (/blog) │ │ └── post/ │ │ └── [...post].astro # Catch-all route for blog posts (/blog/post/*) │ └── [...slug].astro # Catch-all route for CMS pages (e.g. /about, /product/123) │ ├── components/ │ ├── common/ # Shared layout/UI (Header, Footer, Layout, etc.) │ ├── ui/ # UI widgets like cards, buttons, filters │ └── content-types/ # React components for each dotCMS Content Type │ ├── Banner.tsx │ ├── Product.tsx │ └── index.ts │ ├── hooks/ # Custom React hooks │ ├── useDebounce.ts │ └── useEditMode.ts │ ├── integrations/ │ └── dotcms/ │ ├── dotCMSClient.ts # dotCMS API client setup │ ├── queries.ts # dotCMS content fetching │ └── isEditMode.ts # Detect UVE/edit mode │ ├── pages-templates/ # React page templates (can use hooks) │ ├── DotCMSPage.tsx │ ├── BlogListingPage.tsx │ └── DetailPage.tsx │ ├── views/ # Composite sections (not routed) │ ├── HeroWithProducts.tsx │ └── DestinationSection.tsx │ └── styles/ └── global.css
Understanding the Structure#
This project uses Astro's file-based routing with .astro
components for SSR and React components for interactivity and client-side rendering.
1. Astro Pages (src/pages/
)#
- Astro automatically routes files in this folder.
- Use
.astro
files for SSR-friendly rendering and route matching.
Examples:
/blog
→pages/blog/index.astro
/blog/post/hello-world
→pages/blog/post/[...post].astro
/about
,/product/123
→pages/[...slug].astro
Use Astro.params
to access route params, e.g.:
const { slug } = Astro.params; // or `post` in [...post].astro
2. Components (src/components/
)#
common/
: Shared layout elements likeHeader
,Footer
,Layout
.ui/
: Visual widgets likeCard
,Button
,FilterToggle
.content-types/
: React renderers for dotCMS Content Types.
You’ll need one component per dotCMS Content Type — for example:
Product.tsx
,BlogPost.tsx
,Banner.tsx
.
3. Page Templates (src/pages-templates/
)#
-
These are React components used inside
.astro
pages to handle:- hooks (
useEditMode
) - dynamic rendering based on CMS content type
- client-side logic for editor/live-preview
- hooks (
4. Views (src/views/
)#
- Reusable composite components, not routed directly.
- Use them to organize sections like
HeroWithProducts
,DestinationSection
, etc.
5. dotCMS Integration (src/integrations/dotcms/
)#
dotCMSClient.ts
: Fetch layer (REST or GraphQL)queries.ts
: Common CMS data queriesisEditMode.ts
: Detect if in dotCMS UVE or Edit mode
How the Content is Fetched from dotCMS#
Content in this integration is fetched using the @dotcms/client
package, which provides a streamlined way to communicate with the dotCMS API. This client handles authentication, request formatting, and response parsing automatically.
The process works as follows:
- First, we create a configured client instance in
src/utils/dotCMSClient.js
- This client uses the environment variables to connect to your dotCMS instance
- When a page is requested, we use this client to fetch the page data along with its content
- All API requests are managed through this central client for consistency
Here's how the client is configured:
import { createDotCMSClient } from "@dotcms/client"; export const dotCMSClient = createDotCMSClient({ dotcmsUrl: process.env.NEXT_PUBLIC_DOTCMS_HOST, authToken: process.env.NEXT_PUBLIC_DOTCMS_AUTH_TOKEN, siteId: process.env.NEXT_PUBLIC_DOTCMS_SITE_ID, requestOptions: { cache: "no-cache", } });
And here's a typical page fetching function:
export const getDotCMSPage = async (path, searchParams) => { try { return await dotCMSClient.page.get(path, searchParams); } catch (e) { console.error("ERROR FETCHING PAGE: ", e.message); return null; } };
Learn more about the @dotcms/client
package here.
How to Render Your Page#
The rendering process for dotCMS content in Astro involves several key components working together:
- Page Templates: Define the overall layout and structure
- DotCMSBodyLayout: A component that renders the page content structure
- Content Type Components: Custom React components that render specific Content Types from dotCMS
- useEditableDotCMSPage: A hook that makes the page editable in the UVE
When a page is rendered:
- The page data is fetched from dotCMS
- The
useEditableDotCMSPage
hook prepares it for potential editing - The
DotCMSBodyLayout
component renders the page structure - Each content item is rendered by its corresponding React component
Here's how this looks in code:
"use client"; import { DotCMSBodyLayout, useEditableDotCMSPage } from "@dotcms/react"; // Define custom components for specific Content Types // The key is the Content Type variable name in dotCMS const dotComponents = { dotCMSProductContent: MyCustomDotCMSProductComponent, dotCMSBlogPost: BlogPostComponent } export function MyPage({ page }) { const { pageAsset, content } = useEditableDotCMSPage(page); return ( <div> <DotCMSBodyLayout page={pageAsset} components={dotComponents} /> </div> ); }
[!IMPORTANT]
- The
useEditableDotCMSPage
hook will not modify thepage
object outside the editor- The
DotCMSBodyLayout
component renders both the page structure and content- Custom components defined in
dotComponents
will be used to render Content Types
Learn more about the @dotcms/react
package here.
How dotCMS Routes Pages#
dotCMS allows a single page to be accessed via multiple URL paths (e.g., / and /index for the same "Home" page). This flexibility means your Angular application needs to handle these variations.
To ensure all paths to the same content are properly managed and to prevent 404/500 errors, we recommend using a catch-all route strategy in Angular.
How to Implement in Astro:
Create a dynamic route using [...slug].astro
in your src/pages
directory. This catch-all route will handle any undefined paths, allowing you to fetch content from dotCMS based on the full URL. The slug
parameter will contain the full path segments, which you can use to request the corresponding content from dotCMS.
You can learn more about Astro routing strategies here
Content Type to React Component Mapping#
One of the key concepts in this integration is mapping dotCMS Content Types to React components. This mapping tells the framework which React component should render which type of content from dotCMS.
How the mapping works:
- Each key in the mapping object must match exactly with a Content Type variable name in dotCMS
- Each value is a React component that will be used to render that specific Content Type
- When content is rendered, the contentlet data from dotCMS is passed as props to your component
// Example of mapping dotCMS Content Types to React components const dotComponents = { // The key "DotCMSProduct" must match a Content Type variable name in dotCMS DotCMSProduct: ProductComponent, // The key "DotCMSBlogPost" must match a Content Type variable name in dotCMS DotCMSBlogPost: BlogPostComponent }
What happens at runtime:
- When dotCMS content of type "DotCMSProduct" is encountered on a page:
- The
ProductComponent
is rendered - The contentlet data is passed as props to
ProductComponent
- The
- Your component then has access to all fields defined in that Content Type
Example of a component receiving contentlet data:
// The props passed to this component will be the contentlet data from dotCMS function ProductComponent(props) { // Access fields defined in the DotCMSProduct Content Type const { title, price, description, image } = props; return ( <div className="product"> <h2>{title}</h2> <img src={image.url} alt={title} /> <p className="price">${price}</p> <p>{description}</p> </div> ); }
This pattern allows you to create custom rendering for each type of content in your dotCMS instance, while maintaining a clean separation between content and presentation.
This mapping should be passed to the DotCMSBodyLayout
component as shown in the previous section.
Learn more about dotCMS Content and Components:
- Understanding Content Types in dotCMS - In-depth explanation of content types and their structure
- Contentlets in dotCMS - Learn how individual content items (contentlets) work
- @dotcms/react Documentation - Complete reference for the React components library
Conclusion#
This example demonstrates the powerful integration between dotCMS and Astro, enabling fully editable and dynamic web pages. By leveraging dotCMS as a headless CMS and Astro for front-end rendering, you can create high-performance websites that offer both developer flexibility and content editor ease-of-use.
Key benefits of this approach include:
- Separation of concerns: Content management in dotCMS, presentation in Astro
- Visual editing: In-context editing with the Universal Visual Editor
- Performance: Astro server-side rendering and optimization
- Flexibility: Custom React components for different content types
- Developer experience: Modern JavaScript tooling and frameworks
Learn More#
To deepen your understanding of this integration, explore these official dotCMS resources:
- JavaScript SDK: React Library - Documentation for the @dotcms/react package, including components and hooks
- Universal Visual Editor - Learn more about the visual editing capabilities
- Content in dotCMS - Understanding content types and content management in dotCMS
Additional resources:
main
Found an issue with this documentation? Report it on GitHub