Skip to content

Payload CMS & Astro

Add content to your Astro project using Payload as a CMS

PayloadCMS is a headless open-source content management system that can be used to provide content for your Astro project.

  1. An Astro project - If you don’t have an Astro project yet, our Installation guide will get you up and running in no time.
  2. A MongoDB database - PayloadCMS will ask you for a MongoDB connection string when creating a new project. You can set one up locally or use MongoDBAtlas to host a database on the web for free.
  3. A PayloadCMS REST API - Create a PayloadCMS project and connect it to your MongoDB database during the setup.

Configuring Astro for your PayloadCMS collection

Section titled “Configuring Astro for your PayloadCMS collection”

Your Payload project template will contain a file called Posts.ts in src/collections/. If you did not choose a template during installation that created a content collection for you, you can create a new Payload CMS Collection by adding this configuration file manually. The example below shows this file for a collection called posts that requires title, content, and slug fields:

src/collections/Posts.ts
import { CollectionConfig } from "payload/types";
const Posts: CollectionConfig = {
slug: "posts",
admin: {
useAsTitle: "title",
},
access: {
read: () => true,
},
fields: [
{
name: "title",
type: "text",
required: true,
},
{
name: "content",
type: "text",
required: true,
},
{
name: "slug",
type: "text",
required: true,
},
],
};
export default Posts;

Fetch your PayloadCMS data through your site’s unique REST API URL and the route for your content. (By default, PayloadCMS will mount all routes through /api.) Then, you can render your data properties using Astro’s set:html="" directive.

Together with your post, PayloadCMS will return some top-level metadata. The actual documents are nested within the docs array.

For example, to display a list of post titles and their content:

src/pages/index.astro
---
import HomeLayout from "../layouts/HomeLayout.astro";
const res = await fetch("http://localhost:5000/api/posts") // http://localhost:4321/api/posts by default
const posts = await res.json()
---
<HomeLayout title='Astro Blog'>
{
posts.docs.map((post) => (
<h2 set:html={post.title} />
<p set:html={post.content} />
))
}
</HomeLayout>

Create a blog index page src/pages/index.astro to list each of your posts with a link to its own page.

Fetching via the API returns an array of objects (posts) that include, among others, the following properties:

  • title
  • content
  • slug
src/pages/index.astro
---
import HomeLayout from "../layouts/HomeLayout.astro";
const res = await fetch("http://localhost:5000/api/posts") // http://localhost:4321/api/posts by default
const posts = await res.json()
---
<HomeLayout title='Astro Blog'>
<h1>Astro + PayloadCMS 🚀</h1>
<h2>Blog posts list:</h2>
<ul>
{
posts.docs.map((post) =>(
<li>
<a href={`posts/${post.slug}`} set:html={post.title} />
</li>
))
}
</ul>
</HomeLayout>

Using the PayloadCMS API to generate pages

Section titled “Using the PayloadCMS API to generate pages”

Create a page src/pages/posts/[slug].astro to dynamically generate a page for each post.

src/pages/posts/[slug].astro
---
import PostLayout from "../../layouts/PostLayout.astro"
const {title, content} = Astro.props
// The getStaticPaths() is required for static Astro sites.
// If using SSR, you will not need this function.
export async function getStaticPaths() {
let data = await fetch("http://localhost:5000/api/posts")
let posts = await data.json()
return posts.docs.map((post) => {
return {
params: {slug: post.slug},
props: {title: post.title, content: post.content},
};
});
}
---
<PostLayout title={title}>
<article>
<h1 set:html={title} />
<p set:html={content} />
</article>
</PostLayout>

To deploy your site visit our deployment guide and follow the instructions for your preferred hosting provider.