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)
  • 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:

PackagePurposeDescription
@dotcms/clientAPI CommunicationCore API client for fetching content from dotCMS
@dotcms/reactUI ComponentsReact components and hooks for rendering dotCMS content
@dotcms/uveVisual EditingUniversal Visual Editor integration
@dotcms/typesType SafetyTypeScript 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 NamePassword
admin@dotcms.comadmin

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:

  1. Go to the dotCMS admin panel.
  2. Click on System > Users.
  3. Select the user you want to create the API Key for.
  4. 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:

  1. Browse to Settings > Apps.
  2. Select the built-in integration for UVE - Universal Visual Editor.
  3. Select the site that will be feeding the destination pages.
  4. 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:

  1. Log in to the dotCMS admin panel
  2. Browse to Site > Pages
  3. Open the page you want to edit
  4. The page will be rendered in the editor with your Astro front end
  5. 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:

  1. Content Creation: Content editors create and manage content in dotCMS
  2. Content Delivery: Astro fetches content from dotCMS using the API client
  3. Content Rendering: React components render the fetched content
  4. 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:

  • /blogpages/blog/index.astro
  • /blog/post/hello-worldpages/blog/post/[...post].astro
  • /about, /product/123pages/[...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 like Header, Footer, Layout.
  • ui/: Visual widgets like Card, 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

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 queries
  • isEditMode.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:

  1. First, we create a configured client instance in src/utils/dotCMSClient.js
  2. This client uses the environment variables to connect to your dotCMS instance
  3. When a page is requested, we use this client to fetch the page data along with its content
  4. 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:

  1. Page Templates: Define the overall layout and structure
  2. DotCMSBodyLayout: A component that renders the page content structure
  3. Content Type Components: Custom React components that render specific Content Types from dotCMS
  4. 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 the page 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:

  1. Each key in the mapping object must match exactly with a Content Type variable name in dotCMS
  2. Each value is a React component that will be used to render that specific Content Type
  3. 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:

  1. When dotCMS content of type "DotCMSProduct" is encountered on a page:
    • The ProductComponent is rendered
    • The contentlet data is passed as props to ProductComponent
  2. 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:

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:

Additional resources:

Branch: main

Found an issue with this documentation? Report it on GitHub

    Astro Example | dotCMS Dev Site