Astro + Decap in 2026
Source: Dev.to
I finally started working on a project I’d been thinking about for a while: an easy‑to‑maintain portfolio blog for photography and architecture.
I used this opportunity to explore Decap, a git‑based CMS that I’d wanted to try for some time but never got around to. A few years ago I discovered the project while thinking about doing something similar.
I really enjoy working with Astro, and one thing I’ve often wished for when writing for my personal blog is a visual interface that reduces the friction of publishing content. I like my site to be static—I don’t need (and don’t want) a database, even a managed one—but I do want a nice interface to write my posts that isn’t an IDE or Obsidian, something a bit more customized for my particular blog.
It took a little longer than expected to get things working, so I decided to write this post to help others who are thinking about using the same stack.
Installing Decap
From the docs I saw there were two ways of installing Decap:
- Use a CDN version.
- Use a package manager like
npm.
I chose the second option, but I felt a bit lost: then what? where do I import and call the module?
Quick note about auth
I didn’t care about auth at the moment; I just wanted the editor. This makes me believe there is room for another solution in this space, and I didn’t want to create an actual remote repository for the test. I have a local repository, but I didn’t want to push it to GitHub or GitLab.
So I was looking for the minimal installation, even if it took longer to get it right.
Basic structure with Astro
1. config.yml in /public
The config file must live in the public folder because we’ll use an Astro page for the index, and it will reference files from the public root.
# when using the default proxy server port
local_backend: true
backend:
name: proxy
proxy_url: "http://localhost:8081/api/v1"
media_folder: "/src/assets/images/uploads"
collections:
- name: posts
folder: /src/pages/blog
label: "Posts"
fields:
- label: Title
name: title
widget: string
2. Admin route (/admin)
Create /src/pages/admin.astro:
---
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Admin – Decap CMS</title>
</head>
<body>
<script type="module">
import CMS from "decap-cms-app";
CMS.init();
</script>
</body>
</html>
Explanation – The script is essentially the same code that appears in the Decap docs. I’m providing a bit more context because it can be confusing the first time you set it up. All the information is taken from the official docs and the repositories.
Additional notes
1. Minimal config.yml
The documentation lists many configuration options (see here), but it lacks a concise starter example.
Instead of placing config.yml in /public, you could add a <script> tag in the HTML:
<!-- Example placeholder for inline config -->
<script type="module">
// Inline Decap config could go here
</script>
as described in the Decap docs and Astro’s guide. I prefer the public‑folder approach because it keeps the configuration in a single place.
2. Local repository
I first tried the test-repo backend; it’s handy for quick checks but completely ephemeral, so it wasn’t suitable for a real project.
The Working with a local repository guide (link) is exactly what I needed, but it doesn’t spell out the required backend config. The proxy configuration I used comes from the decap-server README.
3. CMS.registerPreviewTemplate
This line appears in the Install Decap CMS and Manual initialization sections. It’s useful for registering a custom preview component (a React component that renders collection data), but it’s not required for a basic setup. You can safely omit it until you need custom previews.
4. Running with a local repository
When running locally you need a local API because Decap CMS relies on Git. The idea is to avoid adding other types of storage, which would defeat the purpose of a git‑based workflow.
To start the local proxy server:
npx decap-server
The server will listen on http://localhost:8081/api/v1 (matching the proxy_url in config.yml). With local_backend: true, Decap CMS will talk to this server, committing changes directly to your local Git repository.
TL;DR checklist
-
Add
config.ymlto/public(or reference it via a<script>tag). -
Create
/src/pages/admin.astrowith the script that imports and initializes Decap. -
Install the packages:
npm install decap-cms-app decap-server -
Run the local proxy:
npx decap-server -
Start your Astro dev server (
npm run dev) and visit/admin.
That’s it! You now have a minimal, git‑backed CMS for your Astro blog without any external database or authentication layer. Feel free to expand with custom previews, authentication, or a remote Git provider when you’re ready. Happy publishing!
Running a Local Server
You can run a local server on a different port from your dev server using decap-server:
npx decap-server
See the guide Working with a Local Git Repository for details.
A More Encapsulated Alternative
Another option—used in the (now‑archived) Astro Decap CMS Starter from the official Astro docs (CMS guide)—is to load Decap CMS from the CDN and serve a static HTML file from the /public folder.
From a technical standpoint this works fine:
- Decap boots itself, so Astro does very little at build time.
- Content management is completely independent of the Astro build process.
A More Customized Version
If you’ve read this far, you’ll see I’ve already made a few choices. It’s a matter of personal preference, but here’s the approach I consider the best and why I prefer it over the alternatives.
Key Benefits
- Code‑based configuration instead of
config.yml. - No pollution of the
/publicfolder. - Easy to extend/customize.
- Privacy‑first: Git‑based, but no need to expose credentials.
Implementation
I created an admin route at /src/pages/admin. The page contains a minimal HTML file that:
- Does not use the regular layout.
- Has only a
<script>tag that loads and configures Decap CMS. - Stores uploads in
/src/assetsso Astro can process them later. - Feels like an automation of my regular workflow rather than a separate system.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Astro Admin</title>
</head>
<body>
<script type="module">
import CMS from "decap-cms-app";
const config = {
localBackend: true,
backend: {
name: "proxy",
proxy_url: "http://localhost:8081/api/v1",
},
load_config_file: false,
media_folder: "/src/assets/images/",
collections: [
{
name: "posts",
label: "Posts",
folder: "src/blog",
create: true,
fields: [
{ label: "Title", name: "title", widget: "string" },
{ label: "Body", name: "body", widget: "markdown" },
{ label: "Created", name: "created", widget: "datetime" },
{ label: "Tags", name: "tags", widget: "list" },
],
},
],
};
CMS.init({ config });
</script>
</body>
</html>
The manual initialization process is described in Customizing Decap CMS → Manual Initialization. The line window.CMS_MANUAL_INIT = true is no longer required.
Authentication
I deliberately left authentication out for now. I don’t need it, and adding unnecessary authentication could introduce security vulnerabilities without providing significant benefits.