Hugo

Using Decap CMS to Add a Web Editor to Your Hugo Site

Hugo is fast and file-based, but its editing experience is entirely command-line: you write Markdown in a text editor, commit to Git, and push to trigger a build. For solo developers this is fine. For publications with non-technical contributors, it is a significant barrier. Decap CMS (formerly Netlify CMS) solves this by adding a browser-based editorial interface to Hugo without abandoning the static site architecture.

What Decap CMS Is

Decap CMS is an open-source, Git-backed content management interface. It sits on top of your Hugo site as a static single-page application, authenticated through your Git provider (GitHub, GitLab, or Bitbucket). When an editor creates or edits content through the Decap interface, Decap commits changes to your Git repository directly. Your build pipeline picks up those commits and rebuilds the site.

The result is a familiar editing UI for contributors while maintaining the static site architecture underneath. Content remains in Markdown files in your repository. Build and deployment work exactly as before.

Adding Decap CMS to a Hugo Site

Step 1: Create the Admin Directory

Create a folder at static/admin/ in your Hugo project. Everything inside static/ is copied verbatim to the built site, so static/admin/ will be accessible at yoursite.com/admin/.

Inside static/admin/, create two files:

index.html:

<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Content Manager</title>
</head>
<body>
  <script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
</body>
</html>

config.yml:

backend:
  name: github
  repo: your-username/your-repo-name
  branch: main

media_folder: static/images/uploads
public_folder: /images/uploads

collections:
  - name: "posts"
    label: "Posts"
    folder: "content/posts"
    create: true
    slug: "{{slug}}"
    fields:
      - { label: "Title", name: "title", widget: "string" }
      - { label: "Publish Date", name: "date", widget: "datetime" }
      - { label: "Draft", name: "draft", widget: "boolean", default: false }
      - { label: "Tags", name: "tags", widget: "list", default: [] }
      - { label: "Featured Image", name: "featured_image", widget: "string", required: false }
      - { label: "Body", name: "body", widget: "markdown" }

Step 2: Configure Authentication

Decap requires OAuth authentication against your Git provider. For GitHub, you need to register a GitHub OAuth app and set up an authentication endpoint.

The simplest path for Netlify-hosted sites is Netlify Identity, which handles the OAuth flow for you:

  1. Enable Netlify Identity in your site’s Netlify dashboard
  2. Enable Git Gateway under Identity → Services
  3. Add this script to your static/admin/index.html (before the Decap script):
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>

And add this to your site’s base template <head> and <body>:

<!-- In <head> -->
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>

<!-- Before closing </body> -->
<script>
  if (window.netlifyIdentity) {
    window.netlifyIdentity.on("init", user => {
      if (!user) {
        window.netlifyIdentity.on("login", () => {
          document.location.href = "/admin/";
        });
      }
    });
  }
</script>

For non-Netlify hosting, configure an external OAuth provider or use the implicit flow directly with GitHub.

Step 3: Define Your Content Collections

The config.yml collections array maps to your Hugo content structure. Configure each section of your site:

collections:
  - name: "posts"
    label: "Posts"
    folder: "content/posts"
    create: true
    slug: "{{year}}-{{month}}-{{day}}-{{slug}}"
    fields:
      - { label: "Title", name: "title", widget: "string" }
      - { label: "Date", name: "date", widget: "datetime" }
      - { label: "Draft", name: "draft", widget: "boolean", default: false }
      - label: "Tags"
        name: "tags"
        widget: "list"
        field: { label: "Tag", name: "tag", widget: "string" }
      - { label: "Body", name: "body", widget: "markdown" }

  - name: "pages"
    label: "Pages"
    files:
      - label: "About"
        name: "about"
        file: "content/about.md"
        fields:
          - { label: "Title", name: "title", widget: "string" }
          - { label: "Body", name: "body", widget: "markdown" }

Available Widgets

Decap CMS provides widgets for common content types:

  • string — single-line text
  • text — multi-line text (no Markdown formatting)
  • markdown — rich Markdown editor with preview
  • number — numeric input
  • boolean — true/false toggle
  • datetime — date and time picker
  • image — image upload with media library
  • file — file upload
  • select — dropdown from defined options
  • list — repeating field of any other widget type
  • object — grouped fields as a single nested structure
  • relation — reference to content in another collection

Preview and Workflow

By default, Decap saves content by committing directly to your main branch, which triggers a rebuild. For larger editorial teams, enable the editorial workflow feature:

publish_mode: editorial_workflow

With editorial workflow enabled, new content is saved as a draft PR against the main branch. Editors can move content through Draft → In Review → Ready states in the CMS UI, and content is only merged (and thus published) when explicitly approved.

Limitations to Know

Decap is a good solution for adding a web-based editing interface to Hugo, but it is not a full CMS. Rich document editing features, inline image resizing, complex layout tools, and real-time collaboration are not part of the package. It is best understood as a structured form interface for creating Markdown files — that covers the majority of what independent publishers need, but not everything.

For teams that need a more sophisticated editorial experience, Tina CMS offers a more advanced alternative with inline editing and visual previews directly on the rendered site.