astro-payload-template

Astro frontend wired to a Payload CMS backend with a lightweight live preview approach

astro-payload-template preview

Overview

Summary generated from the README

Sets up a split project with a Payload CMS backend and an Astro frontend, based on the blank Payload template with Posts, Media and a few globals added. The frontend uses static generation for main routes and server rendering for preview routes, and fetches content through Payload's REST API. SQLite is the default database, and the two apps run in separate terminals.

Features

  • Astro frontend with static pages and server-rendered preview routes
  • Payload backend with Posts and Media collections plus Header and Landing Page globals
  • Live preview that reloads the page when a document is saved in the admin panel
  • Alternative preview script using Payload live preview hooks and Lexical HTML conversion
  • Header and hero components driven by Payload globals, plus a blog template
  • Tailwind CSS with the Typography plugin and SQLite by default

Good for

  • Building a new site that pairs an Astro frontend with Payload as a headless CMS
  • Learning how to implement live preview in Astro without the full Payload hooks
  • Launching a small blog or landing site with editable header and hero content

From the author

A template to demonstrate how to connect an Astro frontend and a Payload CMS backend including live preview.

Get started

This repository is a GitHub template: create your own copy of it in one click.

Create a repository from this template

README

Astro and Payload CMS Starter with Live Preview

This starter is based on the default blank Payload template with basic collections and configuration added for demonstration purposes. The default database is SQLite to reduce external dependencies. Just clone the repo and start.

Features

  • Astro Frontend: SSG on primary routes and SSR on /preview/ routes
  • Payload CMS Backend
  • Live Preview: Eschews "true" live preview in favor of a simpler approach (see Live Preview)
  • Pre-built Components: Header and hero component that use Payload globals for limited editing + blog template.
  • Use of Payload's REST API
  • Tailwind CSS + Typography plugin with basic styling

Project Structure

├── backend/          # Payload CMS
│   ├── src/
│   │   ├── collections/  # Content collections (Posts, Media)
│   │   ├── globals/      # Global configs (Header, Landing Page)
│   │   └── payload.config.ts
│   ├── Dockerfile        # Default Payload Dockerfile
│   └── docker-compose.yml
│
├── frontend/         # Astro site
│   ├── src/
│   │   ├── components/
│   │   ├── layouts/
│   │   ├── pages/
│   │   │   └── preview/ # Preview routes (SSR)
│   │   └── lib/ # Contains function for fetching globals on both preview and production routes
│   └── astro.config.mjs

Purpose

  • Be usable as a template for projects that combine Payload and Astro.
  • Offer an example of an unorthodox implementation of live preview that is highly flexible.

Quick Start

  1. Use this template

    # Create from template (if using GitHub template feature)
    # OR clone directly
    git clone https://github.com/frockett/astro-payload-starter.git my-project
    cd my-project
    
  2. Install Dependencies

    cd frontend/ && npm install
    cd backend/ && npm install
    
  3. Copy env.example files and set PAYLOAD_SECRET

    cp frontend/.env.example frontend/.env
    cp backend/.env.example backend/.env
    
  4. Start development

    # Use two terminals
    
    # Terminal 1
    cd frontend/ && npm run dev
    
    # Terminal 2
    cd backend/ && npm run dev
    

Environment Variables

# frontend/.env
PAYLOAD_URI=http://localhost:3000

# backend/.env
DATABASE_URI=file:./testing-project.db
PAYLOAD_SECRET=YOUR_PAYLOAD_SECRET
CLIENT_URI=http://localhost:4321
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000

Live Preview

This starter uses the following implementation of Live Reload:

// Inside src/components/LivePreview.astro
<script is:inline>
  window.addEventListener(
    'message',
    (event) => {
      if (event.data.type === 'payload-document-event') {
        // reload the page whenever a document is saved in the admin panel to get the latest data
        location.reload()
      }
    },
    false, // Add false to ensure event bubbles up through iframes
  )
</script>

This approach does not make use of Payload's live preview hooks. Instead it listens for the payload event type that indicates an update has been saved, and then reloads the entire SSR route. This method is much simpler than the default implementation.

You can improve editing UX by decreasing the autosave interval. In this template it is set to 500ms.

Credit for this implementation goes to Jens from the Payload Discord server.

Alternative Live Preview

In src/pages/preview/blog/[slug].astro you can find an alternative implementation that does make use of Payload's hooks.

<!-- ALTERNATIVE SCRIPT USING PAYLOAD LIVE PREVIEW HOOKS -->
<script>
  import { subscribe, ready } from "@payloadcms/live-preview";
  import { convertLexicalToHTML } from "@payloadcms/richtext-lexical/html";

  const serverUrl = "http://localhost:3000";

  subscribe({
    callback: (mergedData) => {

      if (mergedData.title) {
        const titleElement = document.querySelector(
          '[data-text-field="title"]',
        );
        if (titleElement) {
          titleElement.textContent = mergedData.title;
        }
      }

      if (mergedData.content) {
        const contentElement = document.querySelector(
          '[data-text-field="content"]',
        );
        if (contentElement) {
          try {
            const html = convertLexicalToHTML({ data: mergedData.content });
            contentElement.innerHTML = html;
          } catch (error) {
            console.error("Failed to convert rich text:", error);
            contentElement.innerHTML = "<p>[Error converting rich text]</p>";
          }
        }
      }
    },
    serverURL: serverUrl,
  });

  ready({
    serverURL: serverUrl,
  });
</script>

This approach offers "true" live preview but has the disadvantage of requiring implementation for every field type and layout change. The script has been preserved for reference.

More Starters & boilerplates templates

astroad screenshot

astroad

Astro frontend and Payload CMS with MongoDB, run in Docker and deployed through GitHub Actions

166
v?
Other
Updated 1 years ago
payload-cms-boilerplate screenshot

payload-cms-boilerplate

Blank Payload 3 and Next.js 16 starter with Postgres, Tailwind, shadcn/ui primitives and a built-in SEO module

19
v3
Next.js
Updated 2 months ago
mi-proyecto-2026 screenshot

mi-proyecto-2026

Blank Payload 3 starter on Next.js 16 with Turso SQLite storage and Cloudflare R2 media uploads

12
v3
Next.js
Updated 4 days ago