How to Use Keystatic: The Beginner's Guide (First Config, Collections, Markdoc and the Reader)

CodexFuse Team · 2026-11-01T09:59:28.533Z · 11 min read

How to use Keystatic, the free git-based CMS: first config, storage modes, your first collection, the Markdoc rule, the Reader API, and deployment.

What Is Keystatic?

Keystatic is a free, open-source, git-based CMS that stores your content as files — Markdoc, YAML, and JSON — right inside your site's Git repository, and gives non-developers a polished Admin UI to edit that content without touching code. There is no database server, no per-seat billing, and no hosted API in the middle: the content is plain files in your repo, so your Git history is your audit log and your backup. Learning how to use Keystatic means four things: choosing a storage mode, describing your content once in keystatic.config.ts, creating entries through the Admin UI, and rendering the files yourself with the Reader API.

This guide covers the complete beginner arc — first config, local versus GitHub storage, your first collection, the Markdoc rule, your first post in the Admin UI, the Reader lesson, and deploying — in one tested walkthrough. One clarification for people comparing options: Keystatic is the git-backed lane of the headless-CMS family. If your content needs a real database, roles, and an API — a different architecture entirely — start with this Directus beginner guide instead.

How to Use Keystatic: The 10-Step First Run

  1. Pick a storage mode: local for development, github for production teams, cloud for managed auth and image hosting.
  2. Install the packages for your framework: @keystatic/core plus @keystatic/next, @keystatic/astro, or @keystatic/remix, plus @markdoc/markdoc.
  3. Create keystatic.config.ts in the project root with your storage kind and an empty collections object.
  4. Define your first collection: label, path with a * wildcard, slug field, and schema fields.
  5. Remember the Markdoc rule: long-form content is Markdoc by default, not plain Markdown.
  6. Start the dev server and open the Admin UI at /keystatic.
  7. Create your first post in the UI and watch it land in your repo as files.
  8. Read the content server-side with the Reader API — never from the browser.
  9. Deploy, then switch the config to GitHub storage for the live admin.
  10. Commit the content files to Git — they are your content, versioned.

Step 1: Choose Your Storage Mode Before Anything Else

The storage decision comes first because everything else follows from it. Keystatic is not a Docker service you install on a server — it embeds inside your site's own repository, so the question is not "where do I host the CMS" but "where do the content files get read from and written to." Keystatic's own configuration documentation lists three storage kinds, and picking the wrong one is the most common beginner mistake.

Storage kindWhat it reads and writesWhen to use itOne gotcha
localFiles on your own machine's diskLearning, solo projects, local developmentNeeds filesystem access — it does not work on edge runtimes like Cloudflare Workers or Vercel Edge
githubYour GitHub repo through the GitHub APIProduction sites and teams editing the live adminNeeds a GitHub token and the Keystatic GitHub App for admin logins
cloudKeystatic CloudTeams that want managed authentication plus image hostingA managed add-on on top of your repo, not a replacement for it

The practical rule: start with local today, plan on github for launch. You can switch the storage kind in one line later — the content files do not change format.

Step 2: Install Keystatic for Next.js or Astro

Installation is two packages plus Markdoc, and the exact pair depends on your framework. The current published version of @keystatic/core on npm is 0.6.9, MIT licensed, with the repository at Thinkmill's GitHub holding roughly 2,494 stars as of the end of October 2026 — small but actively maintained.

Keystatic with Next.js

Keystatic's Next.js guide assumes an existing Next.js 14 project using the app directory. Install with npm install @keystatic/core @keystatic/next @markdoc/markdoc, then mount the Admin UI as a route in your app using makePage from @keystatic/next/ui/app. The editor then lives at the /keystatic route of your own app — no separate server, no separate deploy.

Keystatic with Astro

For Astro, add the Markdoc and React integrations with astro add (Astro's own docs recommend this order), then npm install @keystatic/core @keystatic/astro. The Astro integration mounts the Admin UI at http://127.0.0.1:4321/keystatic while the dev server runs. In this setup Keystatic uses Markdoc for the content entries, which matches the Astro blog flow neatly: each post you create becomes a .mdoc file under src/content/posts, queryable like any Astro content.

Keystatic with Remix

The Remix path is npm install @keystatic/core @keystatic/remix @markdoc/markdoc, and because Keystatic ships ESM only, the Remix guide has you configure server dependencies in the Vite config. One framework, one extra config block — same config file, same collections.

Step 3: Write keystatic.config.ts — Your First Config

Everything Keystatic knows about your content lives in one file: keystatic.config.ts at the project root, exporting a config() from @keystatic/core. The smallest useful version has three things: a storage kind, one collection, and a schema.

// keystatic.config.ts
import { config, fields, collection } from '@keystatic/core';

export default config({
  storage: { kind: 'local' },

  collections: {
    posts: collection({
      label: 'Posts',
      slugField: 'title',
      path: 'content/posts/*',
      format: { contentField: 'content' },
      schema: {
        title: fields.slug({ name: { label: 'Title' } }),
        publishedAt: fields.date({ label: 'Published date' }),
        content: fields.markdoc({ label: 'Content' }),
      },
    }),
  },
});

Read that config like a sentence: store files locally, manage a collection called Posts, derive each entry's slug from its title, put each entry's files under content/posts/, and give every post a title, a date, and a long-form content field. The storage property is required — Keystatic will not run without the storage-kind decision from Step 1. If you work in a monorepo, storage.pathPrefix scopes all paths to one package directory instead of repeating the prefix on every collection.

Step 4: Build Your First Collection (and Learn Singletons)

Keystatic organises content with two structures: collections for repeatable things like posts, and singletons for one-off pages like site settings. The * wildcard in a collection path is mandatory — Keystatic replaces it with the entry's slug — and the path's trailing slash decides the file layout: content/posts/* writes my-first-post.yaml next to a my-first-post/ folder, while content/posts/*/ puts each entry in its own directory with an index.yaml.

Now the Markdoc rule, stated once: Keystatic's default long-form content format is Markdoc — Markdown's stricter, component-friendly cousin — not plain Markdown. Your content field is fields.markdoc, the files it writes end in .mdoc, and you render them with Markdoc's transform and renderers.react functions. That single decision is why Keystatic content can carry custom components while staying valid in Git diffs.

Beyond text, the field library covers the usual blog needs: fields.slug for titles that generate URLs, fields.date, fields.checkbox, fields.array for tag lists, and fields.image with a directory option so uploads land in public/images/... where your framework expects them. Add a singletons object next to collections for one-offs — no * wildcard, default path {singleton-name}/.

Step 5: Create Your First Post in the Admin UI

With the config saved, start your dev server and visit the Admin UI: /keystatic on your app (Astro's default is http://127.0.0.1:4321/keystatic). You get a real CMS dashboard — a Posts collection in the sidebar, a create button, form fields generated from your schema, and the Markdoc editor with preview. Type a title, pick a date, write the content, hit save.

Two things to notice. First, the save is a file write: flip to your editor and you will find a new .mdoc file plus its .yaml frontmatter exactly where your path pattern said it would be. That is the whole mental model — the Admin UI is a pretty face over files. Second, in local mode this route is a development convenience; it edits your local disk. The moment you want editors touching the live site, you move to Step 7 instead of exposing a dev-only route.

Step 6: Read Content with the Reader API — Server-Side Only

Keystatic does not ship content to your pages by itself — you render it yourself, and the Reader API is how. It is createReader from @keystatic/core/reader, and Keystatic's own Next.js and Remix guides both carry the same warning in the same words: the Reader is a Node API, and it must be run server-side. That is the Reader lesson, and it decides your architecture: server components, loaders, or build-time reads — never a browser fetch.

// app/blog/page.tsx (Next.js App Router)
import { createReader } from '@keystatic/core/reader';
import keystaticConfig from '../../keystatic.config';

const reader = createReader(process.cwd(), keystaticConfig);

export default async function BlogIndex() {
  const posts = await reader.collections.posts.all();
  // posts: [{ slug, entry: { title, publishedAt } }, ...]
}

export async function getPost(slug: string) {
  const post = await reader.collections.posts.read(slug);
  // post: { title, publishedAt, content } | null
}

The API reads like your config: reader.collections.posts.all() lists entries, .read(slug) fetches one. For the Markdoc body, run it through Markdoc's transform and render with renderers.react — the exact pair Keystatic's docs name. In local mode the reader resolves straight from your disk, which is why local mode cannot run on edge runtimes: there is no filesystem there to read.

Step 7: Deploy and Switch to GitHub Storage

Deploy your site the way you always deploy that framework — the content files are already in the repo, so a normal build sees them. If this is going on a rented server rather than a platform, this what is VPS hosting guide explains the server side, and the container path is covered in this Docker beginner guide.

The interesting part is the admin on the live site. Flip the storage kind and point at your repo:

export default config({
  storage: {
    kind: 'github',
    repo: 'your-org/your-site',
  },
  // collections unchanged
});

GitHub mode reads and writes through the GitHub API, so you need a fine-grained personal access token in KEYSTATIC_GITHUB_TOKEN, and the Keystatic GitHub App installed on the repo so editors can log in to the Admin UI — the app is what turns "edit in the UI" into commits on your branches. If this is your first GitHub token, this GitHub beginner guide walks through token creation and repo settings. Bonus of the GitHub kind: because the UI commits straight to the repo, every content edit triggers your normal CI pipeline — preview deploys included.

Keystatic vs Decap and Sveltia: the Git-CMS Family

Keystatic is not the first git-based CMS, and the comparison questions are fair. Decap CMS is the other well-known name in this lane, and Sveltia CMS is the newer community UI that speaks Decap's data format — the family shares one idea: content as files, edited through a web UI, versioned in Git. Keystatic's answer to that same idea is distinct in three verified ways: the entire content model is a TypeScript config file you can type-check, the storage layer has three first-class modes (local, GitHub, and Cloud) instead of one, and the Admin UI embeds directly into your Next.js, Astro, or Remix app rather than living as a separate static page.

That distinction decides the pick. If you want the CMS to feel like part of your codebase — typed schema, co-located with the site, content reviewable in pull requests — Keystatic's model fits. If you need the database-backed world instead — users, roles, a REST or GraphQL API over relational data — that is the Directus lane, not this one.

When to Pick Keystatic — and When Not To

Pick Keystatic when your editors are comfortable with Git concepts even if they never touch the terminal, when your content is pages, posts, and docs rather than relational records, and when you want content changes reviewable as pull requests. A marketing site, a docs site, or a personal blog are the textbook fits.

Do not pick it when you need user accounts with fine-grained permissions, when content must be queried relationally, or when non-developers need to edit content on a site whose repo they should never see — that is what the database-backed headless CMS exists for. And do not reach for Keystatic expecting a hosted service to sign up for: there is no Keystatic server to install, only a config file in your repo.

Frequently Asked Questions

Is Keystatic free?

Yes. Keystatic is MIT-licensed open source, free to use in every storage mode. Keystatic Cloud is the optional paid layer for managed authentication and image hosting, but the CMS itself costs nothing and your content always stays in your own repo.

Do I need a database to use Keystatic?

No — that is the point. Content lives as Markdoc, YAML, and JSON files in your Git repository. If your project genuinely needs relational data with users and roles, Keystatic is the wrong tool and a database-backed CMS is the right one.

Should I use local or GitHub storage?

Local for learning and development, GitHub for production and teams. Local mode reads your disk and will not work on edge runtimes; GitHub mode edits through the GitHub API and needs a token plus the Keystatic GitHub App for admin logins. Switching is a one-line config change.

Can I use Keystatic with the Next.js App Router?

Yes — Keystatic's own Next.js guide targets a Next.js 14 app-directory project. The Admin UI mounts as a route via makePage, and you read content in server components with createReader, which keeps everything server-side where the Node API requires it.

Is Keystatic better than Decap CMS?

They solve the same problem — Git-backed editing through a web UI — with different philosophies. Keystatic's distinguishing answers are the TypeScript config, three storage modes, and deep framework embedding; Decap is the longer-established name with its own ecosystem. Choose on architecture fit, not popularity.

Sources

Keystatic docs — Introduction (keystatic.com/docs, storage kinds and quick start); Keystatic docs — Configuration (keystatic.com/docs/configuration, local/github/cloud storage, collections, singletons, path wildcards, Markdoc fields); Keystatic docs — How Keystatic organises your content (keystatic.com/docs/content-organisation, path rules, image directories); Keystatic docs — Adding Keystatic to a Next.js project (keystatic.com/docs/installation-next-js, packages, makePage, Reader API server-side requirement); Keystatic docs — Adding Keystatic to a Remix project (keystatic.com/docs/installation-remix, createReader usage); Astro docs — Keystatic and Astro (v6.docs.astro.build/en/guides/cms/keystatic/, Astro integration, /keystatic admin route, .mdoc output); npm registry — @keystatic/core 0.6.9 (version, MIT license); GitHub API — thinkmill/keystatic (2,494 stars, MIT, updated 2026-10-31); Makerkit docs — Keystatic CMS Setup (makerkit.dev, 2026-10-28, three storage modes, edge-runtime limitation, GitHub token and GitHub App setup); Jan Kraus — A simple guide on how to use Astro with Keystatic (jankraus.net, Reader helper pattern); Maciek Palmowski — Keystatic x Astro (maciekpalmowski.dev, Markdoc choice, image fields); nayankyada.com — Sanity vs Keystatic for Next.js in 2026 (2026-10-14, editor route, reader pattern, Markdoc/MDX); dev.to — Keystatic Has a Free Git-Based CMS (2026-03-29, npm create quickstart, GitHub mode config).

Featured on Twelve Tools Launch Llama Tools Launch your MCP