DEV Community

Cover image for Astro + Decap in 2026
Migsar Navarro
Migsar Navarro

Posted on

Astro + Decap in 2026

This morning I finally started working on a project I had been thinking about for a while, an easy to maintain portfolio blog for photography and architecture.

I used this opportunity to explore Decap, which is a git-based CMS that I wanted to try for some time but never took the time to explore. Some years ago I discovered the project while I was thinking in 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 to publish content. I like my site to be static, I don't need and don't want to have a db even if it is managed, but I want to have a nice interface to write my posts which is not an IDE or Obsidian, something a bit more customized for my particular blog.

It took a little longer than expected to have things working, so I decided to write this post to help others that are thinking about using the same stack.


From the docs I saw there were two ways of installing Decap, use a CDN version or use a package manager like npm. I decided I wanted to use the second option, but I felt a bit lost, then what? where to import and call the module?

Quick note about auth

I really didn't care about auth at the moment, I just wanted the editor, which is something that makes me believe there is room for another solution in this space, and I didn't wanted to have to create an actual repository for the test, I mean, I do have a local repository, but 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

  • Add config.yml in /public. It is needed in public because we are going to use an Astro page for the index, and it will reference files from 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
Enter fullscreen mode Exit fullscreen mode
  • Add /src/pages/admin.astro to have /admin route. This file can be as simple as this:
---

---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <meta name="generator" content={Astro.generator} />
    <title>Astro</title>
  </head>
  <body>
    <script>
      import CMS from "decap-cms-app";

      CMS.init();
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Explanation

As you can see, the script is pretty much the same code that appears in the docs, but I am giving a bit more context here because I had to spend some time putting the information together, and it can be confusing, at least it was for me. All the information is from the docs and the repositories.

1. Minimal config.yaml

It was try and fix. There is a documentation reference for configuration options but it lacks a summary, so it is not very useful for getting started.

Instead of having the config.yml file in /public it is possible to add a <link href="/admin/config.yml" type="text/yaml" rel="cms-config-url" /> tag in the html as described in Configuration options and Astro's Decap CMS Guide. I don't like that option because it spreads configuration across files a little bit more.

2. Local repository

First I tried to use a different backend and saw the test-repo option, it is nice to know things are working, but it is totally ephemeral, so it was not a good solution.

Then I saw the Working with a local repository section, which is just what I needed, but it doesn't say anything about the backend config needed and it was working fine with a config.yml file but it stopped working when I tried the code configuration (which is not relevant for now other than the fact that I presented the "corrected" yaml file), since it used decap-server I looked in that repo and found in the README.md the proxy configuration I presented here.

3. CMS.registerPreviewTemplate

This mysterious line appears in the Install Decap CMS section and later again in the Manual initialization, while it is great to know that the registry is available via the CMS object and it works as expected, that information is not really informative for a first time user.

Apparently it is not needed in any case because I ignored the purpose until a few minutes ago. It is described in Customizing Decap CMS -> Creating custom previews and it allows you to register a custom template for a collection. The template is a React component that will render the data from the collection.

This is totally out of the scope of this post, but I think it is relevant if you, like me, don't like to copy code unless you know it is needed: you don't need it at the moment and you can safely skip that line.

4. Running with local repository

This is something that I don't think is explained in the docs, but probably appears somewhere in the architecture section.

When running locally you need some local API, the idea behind Decap CMS is to use git, it doesn't make sense to add other types of management since it would require a lot of effort to create and maintain.

Therefore, when running locally you need to also run a local server at a different port from your dev server and that's what decap-server is for, you can use it with npx decap-server as indicated in Working with a Local Git Repository.

A more encapsulated alternative

Another alternative, which is the one used in an existing but a bit outdated Astro Decap CMS Starter from offical Astro docs (which doesn't mean that the starter is official, it is actually archived because lack of time from the maintainer) is to use the CDN version of the library and even use a static html inside of the /public folder.

From a technical perspective it is not a bad alternative, since Decap will bootstrap itself there is not much to be processed by Astro at build time and the management of the information can be considered completely autonomous from the development.

A more customized version

If you have read so far you will see, that I've already made a few choices, it is a matter of personal preference, but here I present what I consider the best option and why I prefer it over the alternatives.

These are the important parts:

  1. Code configuration instead of config.yml.
  2. No pollution at /public.
  3. Allows for further customization.
  4. Privacy first, git-based but no need to expose access.

I prefer to have everything in a single place, so I created an admin route in /src/pages/admin there is a minimal HTML file that doesn't use the regular layout, doesn't have anything inside the body but a script tag with the code to load and configure Decap, uploads are made into the /src/assets folder so those can later be processed by Astro, and it feels like an automation of my regular flow instead of a different system.

---

---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <meta name="generator" content={Astro.generator} />
    <title>Astro</title>
  </head>
  <body>
    <script>
      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>
Enter fullscreen mode Exit fullscreen mode

The manual initialization is described in Customizing Decap CMS -> Manual Initialization. Apparently the line window.CMS_MANUAL_INIT = true is not needed anymore.

The main thing that I intentionally left unsolved for now is authentication, I don't need it and I think that configuring something that I don't need would increase security vulnerabilities and offer little gains.

Top comments (0)