Strapi

Strapi is an open-source headless CMS you self-host. Full control over your content schema, API, and data. Pairs perfectly with Astro. Fetch content via REST or GraphQL at build time.

Last updated: 2026-03-29

Setup

Spin up a Strapi instance locally or deploy to a cloud provider. Strapi gives you an admin panel where editors can create and manage content without touching code.

Terminal
# Create a new Strapi project
npx create-strapi-app@latest my-cms --quickstart

# .env (in your Astro project)
STRAPI_URL=http://localhost:1337
STRAPI_TOKEN=your-api-token

Fetch Content

Strapi exposes a REST API by default. Create a helper to fetch content types from your Strapi instance. No SDK needed. Plain fetch works.

Terminal
// src/lib/strapi.js
const STRAPI_URL = import.meta.env.STRAPI_URL;
const STRAPI_TOKEN = import.meta.env.STRAPI_TOKEN;

export async function fetchAPI(endpoint, params = {}) {
  const query = new URLSearchParams(params).toString();
  const res = await fetch(`${STRAPI_URL}/api/${endpoint}?${query}`, {
    headers: {
      Authorization: `Bearer ${STRAPI_TOKEN}`,
    },
  });
  const json = await res.json();
  return json.data;
}

export async function getPosts() {
  return fetchAPI('posts', {
    'populate': '*',
    'sort': 'publishedAt:desc',
  });
}

export async function getPostBySlug(slug) {
  const posts = await fetchAPI('posts', {
    'filters[slug][$eq]': slug,
    'populate': '*',
  });
  return posts[0];
}

Render in Astro

Call your Strapi helper in Astro frontmatter. Content is fetched at build time for static sites. Use webhooks to trigger rebuilds when editors publish new content.

Terminal
---
// src/pages/blog/index.astro
import { getPosts } from '../../lib/strapi';

const posts = await getPosts();
---

<section class="grid gap-6">
  {posts.map((post) => (
    <a href={`/blog/${post.attributes.slug}`}>
      <h2>{post.attributes.title}</h2>
      <p>{post.attributes.excerpt}</p>
      <time>{new Date(post.attributes.publishedAt).toLocaleDateString()}</time>
    </a>
  ))}
</section>

Best Practices

Strapi is flexible. Keep your content types simple and use relations sparingly.