Simple Git CMS

Open source · MIT

The editor your writers use.
The repository you already have.

Articles are Markdown files in your GitHub repository. Simple Git CMS is one static page that reads and writes them through the GitHub API, from the editor’s own browser. No server of your own, and no database.

Try it in your browser View on GitHub How to put it on a site

The demo makes up a repository inside your browser. Nothing to sign in to, nothing sent anywhere.

  • Astro, Hugo & friends
  • One commit per save
  • English · 简体中文 · 日本語
The Simple Git CMS editor, showing an article with a captioned image

Three things it gets out of your way

01

Nothing of yours to run

The editor is a static directory you drop next to your site. It talks to GitHub and to nobody else — so there is no backend to deploy, patch, pay for or watch.

02

Permissions are repository permissions

Whoever can push can edit. No user table, no roles to keep in sync, no second place to revoke access. Who changed what is already in the git history.

03

Publishing is a commit

An article and its images go in as a single commit, so your existing CI builds and deploys the site. After publishing, the top bar follows the GitHub Actions run.

What happens when someone hits Save

The editor A static page on your site
one commit: article.md + images
GitHub API From the browser, with their token
on push
GitHub Actions Your existing build
deploys
Your site Astro, Hugo, anything

Drafts are saved with [skip ci] so they don’t trigger a build. If someone else changed the article while it was open, you are shown their version and yours instead of losing either.

What it does

WYSIWYG that saves clean Markdown

Open an existing article, save it again, and the file is unchanged. No stray HTML, no reformatting.

Images without a trip to Photoshop

Paste, drop or pick several at once. Compressed to webp in the browser, then crop, rotate, caption, place side by side, replace.

Preview in your own layout

The article rendered by your site, at desktop or phone width, including the changes and images you haven’t saved yet.

Drafts, publishing, reverting

Title, date, tags, summary. Save a draft, publish it, revert it to a draft, or delete one — all of it ordinary commits.

Conflicts handled, not ignored

Saving checks the file hasn’t moved underneath you. When it has, you choose between their version and yours.

Sign in with GitHub

A GitHub App redirect that works on phones, with the token refreshed automatically — or paste a fine-grained access token.

Three interface languages

English, 简体中文 and 日本語, switchable in place. Adding a fourth is one file of strings.

A relay that runs anywhere

The sign-in relay is a single dependency-free file: Cloudflare Workers, Deno Deploy, Vercel, Netlify, Bun, or your own Node server.

Putting it on a site

Four steps, and the longest one is writing a config file.

  1. 1

    Build and install the editor

    Into any static directory of your site, so the URL is /editor/. Upgrading is the same two commands; your config.json and logo are left alone.

    npm install
    npm run build
    node scripts/install.mjs ../my-site/public/editor
  2. 2

    Write config.json

    Next to the editor’s index.html. Where the content lives, where images go, what the interface calls itself.

    {
      "repo": "owner/repo",
      "branch": "main",
      "siteUrl": "https://example.com",
      "timeZone": "Asia/Tokyo",
      "auth": { "base": "https://cms-auth.example.com" },
      "collection": {
        "dir": "src/content/news",
        "url": "/news/{id}/"
      },
      "media": { "dir": "public/uploads", "url": "/uploads" }
    }
  3. 3

    Deploy the sign-in relay

    One file, one GitHub App. Cloudflare Workers is the documented route; anything with fetch works.

  4. 4

    Add your editors

    A GitHub account, write access to the repository, and the App installed on it. That’s the whole permission model.

And the files it writes

Frontmatter the editor doesn’t recognise is preserved untouched, so it can edit articles your site already has. A new article’s filename is the minute it was created.

---
title: "A title"
date: 2026-10-21T03:00:00.000Z
tags: ["tag one", "tag two"]
draft: true
---

The body, in Markdown.
![](/uploads/20261021/abc.webp "An image caption")

Where it isn’t the answer

Written down in the README too, because finding out later is worse.

  • Editors need a GitHub account. Letting people in without one would mean running a sign-in service of your own.
  • One article collection per site, with the fields above.
  • The preview converts Markdown in the browser, so Markdown plugins your site adds separately aren’t reflected in it.
  • The GitHub token lives in localStorage — the usual trade-off for an editor with no backend. Serve it from a domain you control.

Read the full list →

Have a look at the code

Three READMEs, a test suite with no network in it, and about 2,000 lines you can read in an afternoon.

AZQ1994/simple-git-cms