Give feedback as an early user and get the docs plus a full website free. Code FRIEND: valid on one-time purchases only.

Configure Your Blog with Decap CMS

This starter ships with a fully working, Git-based blog powered by Decap CMS. This guide shows how the blog is wired across Astro's content collections and the Decap admin, how to configure the post fields, how to connect a login for your client with DecapBridge, and how posts get published, every edit lands back in your GitHub repo as a commit.

Before You Start

Make sure you've read the initial setup guide.

See Quick Setup

How Setup Works

1

Understand

See how the Decap config, the Astro schema, and markdown posts fit together

2

Configure

Set the collection fields and matching content schema

3

Connect

Wire up DecapBridge login with a GitHub token

4

Publish

You and your client write posts from the /admin dashboard

How the Blog Works

Decap CMS is a Git-based CMS, there's no database. Every post is a markdown file in your repo, and a handful of files do all the work.

public/
└─ admin/
   ├─ config.yml                ← Decap CMS config (collection, fields, backend)
   └─ decap-preview-styles.css  ← styles the preview pane
src/
├─ content.config.ts           ← Zod schema that validates post frontmatter
├─ content/
│  └─ blog/
│     ├─ my-first-post.md       ← one markdown / MDX file per post
│     └─ ...
├─ assets/
│  └─ images/
│     └─ blog/                  ← cover images uploaded from the CMS
└─ pages/
   └─ admin.astro              ← loads the Decap dashboard + preview

public/admin/config.yml

Defines your collection, the fields each post has, and which backend handles login.

src/content.config.ts

A Zod schema that validates each post's frontmatter and enables image optimization.

src/content/blog/

One .md or .mdx file per post. The CMS writes files here.

src/assets/images/blog/

Where cover images land when uploaded through the dashboard.

Edits become commits

When someone saves a post in the dashboard, Decap commits the markdown change to your GitHub repo. That commit triggers a rebuild on your host, and the new post goes live, no manual deploy needed.

Configure the Blog Collection

The collection in public/admin/config.yml controls where posts are saved and the fields editors fill in.

The starter already includes the blog collection below. The defaults work out of the box, adjust labels, add fields, or change the upload folders to fit your project. See Decap's configuration docs for every available widget.

# Where uploaded media is stored (in src so Astro can optimize it)
media_folder: src/assets/images/blog
# Same folder via a path alias, used when referencing images in markdown
public_folder: "@assets/images/blog"

collections:
  - name: "blog"          # used in routes and when fetching the collection
    label: "Blog"         # shown in the admin dashboard UI
    folder: "src/content/blog"
    create: true          # let editors create new posts
    fields:
      - { label: "Title", name: "title", widget: "string" }
      - { label: "Description", name: "description", widget: "string" }
      - { label: "Author", name: "author", widget: "string" }
      - { label: "Date", name: "date", widget: "datetime" }
      - { label: "Cover Image", name: "image", widget: "image" }
      - { label: "Image Caption", name: "imageAlt", widget: "string" }
      - { label: "Is it a featured post?", name: "isFeatured", widget: "boolean", default: false }
      - { label: "Body", name: "body", widget: "markdown" }

What each field does

Titletitlestring

The post headline.

Descriptiondescriptionstring

Short summary used in listings and SEO meta tags.

Authorauthorstring

Name shown as the byline.

Datedatedatetime

Publish date, used for sorting.

Cover Imageimageimage

Uploaded to src/assets/images/blog and optimized by Astro.

Image CaptionimageAltstring

Alt text for the cover image.

Is it a featured post?isFeaturedboolean

Toggles whether the post is highlighted on the homepage.

Bodybodymarkdown

The post content, written in rich-text markdown.

The filename is the slug

There's no URL field, Astro uses each post's filename as its slug, so my-first-post.md is served at /blog/my-first-post/.

Where images go

public_folder uses the @assets path alias, so uploaded covers are referenced as @assets/images/blog/... and Astro optimizes them at build time.

Match the Content Collection Schema

Astro validates every post against a typed schema in src/content.config.ts.

The schema uses a glob loader to pick up every .md / .mdx file in the blog folder, and the image() helper so Astro can optimize the cover image. Each field here corresponds to a field in your config.yml.

import { z, defineCollection } from "astro:content";
import { glob } from "astro/loaders";

// Every collection must reflect Decap's config.yml fields
const blogsCollection = defineCollection({
  loader: glob({ pattern: "**/[^_]*.{md,mdx}", base: "./src/content/blog" }),
  schema: ({ image }) =>
    z.object({
      title: z.string(),
      description: z.string(),
      author: z.string(),
      date: z.date(),
      image: image(),
      imageAlt: z.string(),
      isFeatured: z.boolean().optional().default(false),
    }),
});

export const collections = {
  blog: blogsCollection,
};

Keep the schema and config.yml in sync

This is the one rule that trips people up: if you add or rename a field in config.yml, make the same change in content.config.ts. If a post's frontmatter doesn't match the schema, Astro fails the build with a validation error.

What a post file looks like

Each post the CMS creates is a markdown file whose frontmatter matches the schema, followed by the body. You can also create posts by hand using this shape:

---
title: My First Post
description: A short summary of what this post is about.
author: Your Name
date: 2026-06-24T12:00:00.000Z
image: "@assets/images/blog/placeholder.jpg"
imageAlt: Descriptive alt text
isFeatured: false
---

Write your post here using **markdown** or MDX.

Connect Login with DecapBridge

To let you and your client log in without the deprecated Netlify Identity, create a free DecapBridge site that bridges to your repo.

  • 1.Navigate to decapbridge.com and create an account. It's free.
  • 2.Open the dashboard and click Create New Site. You'll be asked to fill in three input fields.

GitHub repository

Must be in user-or-org/repository-name format, e.g. your-name/your-blog.

GitHub access token

A fine-grained personal access token (see the next section for how to create one).

Decap CMS URL

The deployed URL of your admin dashboard, e.g. https://your-site.netlify.app/admin/#/.

Create a GitHub Access Token

DecapBridge needs a fine-grained token to read your markdown and open pull requests with new content.

  1. 1Log into your GitHub account.
  2. 2Click your profile picture (top right, not the repository profile) and click Settings.
  3. 3Scroll down and click Developer Settings.
  4. 4Click Personal access tokens and choose Fine-grained tokens.
  5. 5Click Generate new token and provide your password again if required.
  6. 6Provide a name for the token in the Note field.
  7. 7Set the token’s Expiration to "No expiration".
  8. 8Set Repository access to the desired repository only.

Repository permissions

Under Permissions / Repository permissions, set Read and write access for this repository's Contents and Pull requests. This lets Decap CMS read your markdown and write new content via pull requests.

  1. 9Double-check the permissions, then click Generate token.
  2. 10Copy your token now, you will not be able to see it again.

Don't lose the token

The token is shown only once. Copy it before leaving the page and paste it straight into the DecapBridge GitHub access token field.

Swap in the Backend Snippet

Replace the backend block in your admin config with the snippet from your DecapBridge dashboard.

In public/admin/config.yml, replace the backend block with the snippet from your DecapBridge dashboard. The repo, identity_url, and gateway_url values are all generated for you. It should look something like this:

# Use DecapBridge auth (required)
backend:
  name: git-gateway
  repo: your-name/your-blog # provided by decapbridge
  branch: main
  identity_url: https://auth.decapbridge.com/sites/<your-site-id> # provided by decapbridge
  gateway_url: https://gateway.decapbridge.com # provided by decapbridge

  # Quickly see who did what (optional)
  commit_messages:
    create: Create {{collection}} "{{slug}}" - {{author-name}} <{{author-login}}> via DecapBridge
    update: Update {{collection}} "{{slug}}" - {{author-name}} <{{author-login}}> via DecapBridge
    delete: Delete {{collection}} "{{slug}}" - {{author-name}} <{{author-login}}> via DecapBridge
    uploadMedia: Upload "{{path}}" - {{author-name}} <{{author-login}}> via DecapBridge
    deleteMedia: Delete "{{path}}" - {{author-name}} <{{author-login}}> via DecapBridge
    openAuthoring: Message {{message}} - {{author-name}} <{{author-login}}> via DecapBridge

# Better Decap + Bridge logo (optional)
logo_url: https://decapbridge.com/decapcms-with-bridge.svg

# Add site links in DecapCMS (optional)
site_url: https://your-site.netlify.app

Push and test

Push the change to your repo and test the authentication system. As the admin of the site, your login credentials for the Decap dashboard are the same as your decapbridge.com credentials.

Publish Posts from /admin

This is the day-to-day workflow your client will use, no code, no terminal.

  1. 1Go to https://your-site.com/admin/ and log in with the DecapBridge credentials.
  2. 2Open the Blog collection and click New Blog.
  3. 3Fill in the Title, Description, Author, and Date, upload a Cover Image, optionally flip Is it a featured post?, then write the body in the markdown editor.
  4. 4Click Publish. Decap commits a new markdown file to src/content/blog/, your host rebuilds, and the post appears at /blog/your-filename/.

Invite your client

In your DecapBridge dashboard, add your client as a collaborator. They get their own email and password, they never need a GitHub account to publish.

Preview before publishing

The editor shows a live preview pane next to the form, so your client can see how the post will look before they hit Publish.

Styling the Decap Preview Pane

Custom styles make blog posts in the admin dashboard look similar to the live site.

How it works

  • 1.The preview styles are defined in public/admin/decap-preview-styles.css.
  • 2.The CMS preview script in src/pages/admin.astro pulls the props from the collection, creates the DOM elements, and registers them and the styles for the preview panel to use.

How to update or customize

Edit public/admin/decap-preview-styles.css and the preview pane script in src/pages/admin.astro to match your site's branding or layout changes. See Decap's documentation on customizing the preview pane.

Adding a Local Backend

Enable local backend settings to make content changes from the Decap dashboard during development.

1. Enable the local backend in public/admin/config.yml

+ local_backend: true

2. Install the packages needed to run a local Decap server alongside Astro

We need to run a local Decap server in parallel with astro dev. Install the helpers:

npm install npm-run-all --save-dev
npm install decap-server

3. Update the scripts in package.json

"scripts": {
  "astro": "astro dev",
  "decap": "npx decap-server",
  "dev": "npm-run-all --parallel astro decap"
}

Run it

Now when npm run dev runs, a proxy server for the CMS spins up on localhost:8081. Access the blog locally at http://localhost:4321/admin. While running the local dev server, you won't need to log in to access the admin dashboard.

Your Blog Is Ready

You now have a CMS-powered blog your clients can manage themselves, content lives in markdown, media is optimized automatically, and everything is editable from the /admin dashboard.