Skip to content

Payload CMS & Astro

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;
  1. Import and add both Users (available in all PayloadCMS projects) and any other collections (e.g. Posts) to the available collections in the payload.config.ts file.

    src/payload.config.ts
    import { buildConfig } from "payload/config";
    import path from "path";
    import Users from "./collections/Users";
    import Posts from "./collections/Posts";
    export default buildConfig({
    serverURL: "http://localhost:4321",
    admin: {
    user: Users.slug,
    },
    collections: [Users, Posts],
    typescript: {
    outputFile: path.resolve(__dirname, "payload-types.ts"),
    },
    graphQL: {
    schemaOutputFile: path.resolve(__dirname, "generated-schema.graphql"),
    },
    });

    This will make a new collection called “Posts” appear in your PayloadCMS Dashboard next to the “Users” collection.

  2. Enter the “Posts” collection and create a new post. After saving it, you will notice the API URL appear in the bottom right corner.

  3. With the dev server running, open http://localhost:4321/api/posts in your browser. You should see a JSON file containing the post you have created as an object.

    {
    "docs":[
    {
    "id":"64098b16483b0f06a7e20ed4",
    "title":"Astro & PayloadCMS Title 🚀",
    "content":"Astro & PayloadCMS Content",
    "slug":"astro-payloadcms-slug",
    "createdAt":"2023-03-09T07:30:30.837Z",
    "updatedAt":"2023-03-09T07:30:30.837Z"
    }
    ],
    "totalDocs":1,
    "limit":10,
    "totalPages":1,
    "page":1,
    "pagingCounter":1,
    "hasPrevPage":false,
    "hasNextPage":false,
    "prevPage":null,
    "nextPage":null
    }

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>

Building a blog with PayloadCMS and Astro

Section titled Building a blog with PayloadCMS and Astro

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.

More CMS guides