This episode covers CMS integration with Astro: headless CMS platforms like Contentful, Sanity, and Strapi, content sourcing from Git-based CMS, preview mode and build-time content updates, and authoring workflows and metadata management.

In episode 5 you managed content as local Markdown files. Episode 11 takes content management to the next level: the content management system (CMS). When content is managed by many people — writers, editors, reviewers — a CMS provides a friendly interface without touching code.
You will learn three main approaches: headless CMS platforms like Contentful, Sanity, and Strapi; Git-based CMS like Decap CMS that stores content as files in the repository; and preview mode with build-time content updates.
By the end of the episode, you can choose the right CMS and connect it to Astro through the content layer API you learned in episode 6.
A headless CMS stores content in the cloud and provides an API. Astro fetches that content at build time — the content becomes fast static HTML. Example with Contentful using its SDK:
import contentful from "contentful";
const client = contentful.createClient({
space: import.meta.env.PUBLIC_CONTENTFUL_SPACE,
accessToken: import.meta.env.CONTENTFUL_TOKEN,
});
export async function ambilArtikel() {
const entries = await client.getEntries({
content_type: "artikel",
order: "-fields.tanggal",
});
return entries.items;
}The client.getEntries({ content_type: "artikel" }) pattern uses the Contentful SDK. The CONTENTFUL_TOKEN variable is secret and only runs at build — safe because it is never sent to the browser.
Sanity offers GROQ queries and real-time editing, while Strapi is a self-hosted Node CMS. Both have JavaScript clients that can be used directly in frontmatter. The key is the same: fetch data, validate it with a content layer schema, then render statically.
const query = `*[_type == "artikel"] | order(publishedAt desc)`;
const artikel = await client.fetch(query);The GROQ query above fetches all articles sorted from the newest date. Once the data is in, the next steps are identical to Markdown content.
Git-based CMS stores content as Markdown files in the repository. You write through a web interface, and changes are saved as commits. Decap CMS (formerly Netlify CMS) is the most popular example.
Its configuration is a public/admin/config.yml file:
backend:
name: git-gateway
branch: main
media_folder: public/images
collections:
- name: artikel
label: Artikel
folder: src/content/artikel
fields:
- { name: title, label: Judul }
- { name: published, label: Tanggal, widget: datetime }The folder: src/content/artikel configuration makes new Markdown files land directly in the Astro collection folder. CMS editors do not need to understand file formats — they just fill in a form.
Every change is recorded in git: complete history, review through pull requests, and no cloud service lock-in. Content is treated the same way as code — a practice called content-as-code.
When content changes in the CMS, the Astro page does not change until a rebuild. The solution is a webhook: the CMS notifies the hosting platform on every change, then triggers a new build.
Editor edit konten → CMS webhook → build ulang → deployOn platforms like Netlify or Vercel, the CMS webhook triggers automatic builds. With the content layer, you can add a &v=timestamp parameter to avoid cache during the build.
To review drafts before publishing, build a preview: run a build from a specific branch, or serve a page with draft content from the CMS. Sanity provides real-time preview with GROQ subscriptions; Contentful has a preview API with a separate token. Choose the pattern that fits your budget and team needs.
In episode 5 you already defined content collection schemas. Now that schema becomes the contract between the CMS and the site. Every field in the CMS must match the Zod schema — if not, the build fails and the problem is caught early.
const artikel = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/content/artikel" }),
schema: z.object({
title: z.string(),
published: z.date(),
category: z.enum(["tutorial", "opini", "berita"]),
tags: z.array(z.string()),
}),
});The z.object schema above validates title, date, category, and tags. This field consistency keeps content quality high even when many people write it.
Set a clear flow: draft in the CMS, review by an editor, then publish. Metadata such as slug, excerpt, and cover image must always be present before publishing. A tidy workflow makes the content production process predictable.
Info
Start with a Git-based CMS or Markdown files. Add a cloud headless CMS only when the need for collaboration and non-technical editing is truly pressing.
Episode 11 opens up team-scale content management: headless CMS integration with Contentful, Sanity, and Strapi, content sourcing from Git-based CMS like Decap, preview mode and webhooks for build updates, and authoring workflows with schema as the contract.
The key takeaways:
PUBLIC_.In the next episode 12, we will cover security and best practices: secure headers and Content Security Policy, XSS mitigation and content sanitization, securing API calls and tokens, and protecting sensitive content on static sites. Security becomes a must once your site is online.