Adding Keystatic to an Astro project
This guide assumes you have an existing Astro project with SSR and output: 'hybrid' (or 'server') configured.
If you don't have an existing Astro project, you can create a new one with the following command:
npm create astro@latest
Installing dependencies
Add Astro's integrations for Markdoc and React using the astro add command:
npx astro add react markdoc
You will also need two Keystatic packages:
npm install @keystatic/core @keystatic/astro
Updating the Astro config
Add the keystatic
integration in your astro.config.mjs
file and set the output
mode to hybrid
:
// astro.config.mjs
import { defineConfig } from 'astro/config'
import react from '@astrojs/react'
import markdoc from '@astrojs/markdoc'
+ import keystatic from '@keystatic/astro'
// https://astro.build/config
export default defineConfig({
- integrations: [react(), markdoc()],
+ integrations: [react(), markdoc(), keystatic()],
+ output: 'hybrid',
})
Creating a Keystatic config file
Create a file called keystatic.config.ts
in the root of the project and add the following code to define both your storage type (local
) and a single content collection (posts
):
// keystatic.config.ts
import { config, fields, collection } from '@keystatic/core';
export default config({
storage: {
kind: 'local',
},
collections: {
posts: collection({
label: 'Posts',
slugField: 'title',
path: 'src/content/posts/*',
format: { contentField: 'content' },
schema: {
title: fields.slug({ name: { label: 'Title' } }),
content: fields.markdoc({ label: 'Content' }),
},
}),
},
});
Keystatic is now configured to manage your content based on your schema.
Running Keystatic
You can now launch the Keystatic Admin UI. Start the Astro dev server:
npm run dev
Visit http://127.0.0.1:4321/keystatic
to see the Keystatic Admin UI running.
Keystatic used to require updating your dev
script. It's now managed by the integration, feel free to simplify it!
- "dev": "astro dev --host 127.0.0.1"
+ "dev": "astro dev"
Creating a new post
In our Keystatic config file, we've set the path
property for our posts
collection to src/content/posts/*
.
As a result, creating a new post from the Keystatic Admin UI should create a new content
directory in the src
directory, with the new post .mdoc
file inside!
Go ahead ā create a new post from the Admin UI, and hit save.
You will find your new post inside the src/content/posts
directory:
src
āāā content
āāā posts
āāā my-first-post.mdoc
Navigate to that file in your code editor and verify that you can see the Markdown content you entered. For example:
---
title: My First Post
---
This is my very first post. I am **super** excited.
Rendering Keystatic content
Keystatic provides its own Reader API to pull data from the file system into your frontend. This guide leverages Astro's built-in content collections instead.
Displaying a collection list
The following example displays a list of each post title, with a link to an individual post page:
// src/pages/posts/index.astro
---
import { getCollection } from 'astro:content'
const posts = await getCollection('posts')
---
<ul>
{posts.map(post => (
<li>
<a href={`/posts/${post.slug}`}>{post.data.title}</a>
</li>
))}
</ul>
Displaying a single collection entry
To display content from an individual post, you can import and use Astro's <Content />
component to render your content to HTML:
// src/pages/posts/my-first-post.astro
---
import { getEntry } from 'astro:content'
const post = await getEntry('posts', 'my-first-post')
const { Content } = await post.render()
---
<main>
<h1>{post.data.title}</h1>
<Content />
</main>
If you want to generate pages for all entries of a collection, this Astro guide will help.
Using Astro's <Image /> component
If you want to use The <Image />
component from Astro to display images in your content, this guide will help.
Deploying Keystatic + Astro
Because Keystatic needs to run serverside code and use Node.js APIs, you will need to add an Astro adapter to deploy your project.
You will also probably want to connect Keystatic to GitHub so you can manage content on the deployed instance of the project.