I migrated three Astro sites off Jekyll/Gatsby over the last few years. The content moved cleanly — they’re all markdown + frontmatter + JSON in the repo, exactly the shape Jekyll established a decade ago and Gatsby kept. Astro reads them via content collections; the build is fast; the deploy is rsync.

The piece that doesn’t survive the migration is the editor.

When I worked in Jekyll, I edited markdown in VS Code, ran bundle exec jekyll serve, and pushed to GitHub Pages. That was the entire publishing workflow. It worked because I was the only writer. It stops working the moment anyone non-technical wants to contribute — a sister with a new site, a future client, even me when I just want to fix a typo from my phone.

So you go shopping for a CMS. And almost every modern CMS asks you to throw away the thing that made Jekyll good in the first place: your content as files in your repo.

The git-based vs database-backed split

When I started looking at CMSes, here’s what was on the table:

Database-backed (content goes into a database somewhere):

  • Sanity — hosted “Content Lake”, queried via GROQ
  • Contentful, Storyblok — hosted SaaS
  • Strapi, Directus — self-hosted Node + Postgres/Mongo
  • Payload — self-hosted Node + Mongo (great DX, content still ends up in Mongo)

These are powerful systems with nice editor UX. But each one wants me to import my markdown into a database, then expose it back via an API for Astro to fetch. The files become a one-time export, and ongoing content lives in the database — owned by the SaaS or by whichever DB I’m now running.

Git-based (content stays as files in the repo):

  • Decap CMS (formerly Netlify CMS)
  • Sveltia CMS (modern fork of Decap)
  • Keystatic
  • TinaCMS (drifting toward a hosted backend)
  • Pages CMS, Front Matter CMS (smaller players)

These give you a web-based editor that reads and writes the same markdown files Astro is already consuming. The editor is just a different front-end for the same content. The content is still in git. The build is still a normal Astro build. Nothing else in your stack changes.

For someone coming from Jekyll or Gatsby, this is the natural successor. You don’t relocate your content; you just bolt a friendlier editing surface onto it.

Why “git-based” matters more than the marketing makes it sound

It’s not just about avoiding lock-in — though that’s real. Getting your content out of Sanity or Contentful is a project; it’s never going to be as clean as the files you put in. The bigger thing is what stays the same:

  • The build is unchanged. Astro reads .contents/articles/*.md. Always has, always will. The CMS doesn’t sit in the build path.
  • Existing tooling keeps working. Git history, grep, your CI pipeline, drafts on feature branches, contributor PRs through the normal GitHub flow.
  • Your repo is the source of truth. No “wait, did I edit it on Sanity or in the file?” reconciliation. The file IS the content.
  • Migration is free. You don’t migrate content into the CMS. You point the CMS at the folders where your content already lives. First save you make is a normal git commit.

For this site, the entire CMS “migration” was: write 50 lines of YAML that map collections to my existing .contents/articles/, .contents/case_studies/, .contents/services/ folders, mirroring the zod schemas already in src/content.config.ts. The first time I opened the CMS, all my existing content was already there, ready to edit. No import script. No data validation. No “did anything get lost in translation.”

Try that with a database-backed CMS.

Inside git-based: Keystatic, Decap, Sveltia

That left three real candidates. (TinaCMS is technically git-based but its architecture has shifted toward a hosted editor backend; the line is getting blurry.)

Keystatic has the nicest developer experience. TypeScript schema-as-code, native Astro integration, the schemas could even reuse my zod content collection definitions. It would have been my first pick.

The reason I dropped it is structural, not technical: Keystatic’s admin embeds inside the Astro site as a route at src/pages/keystatic/[...params].astro. Every site that uses Keystatic carries the admin in its build output. For one site that’s fine. For four sites where I wanted one consistent pattern (workspace/websites_cms/<site>/, served at <site>/cms subpath), it fragments the architecture — I’d have embedded admins for some sites and standalone admins for others.

So Keystatic was out, not on its merits but on structural uniformity.

That left Decap and Sveltia. They’re config-compatible (same config.yml, same widget API). On paper they’re swappable. In practice they’re not.

Decap vs Sveltia: the actual comparison

Decap (formerly Netlify CMS) has 19,000 GitHub stars, 5+ years of releases, and basically every feature the docs claim. Sveltia is a Svelte-based fork — 2,400 stars, much nicer editor (dark mode, mobile, ~3× lighter bundle), but a few Decap features are still on its “coming in 1.0” list.

The ones that bit me:

  • registerFieldType (custom per-field form widgets) — Decap has it; Sveltia doesn’t yet. So if you want an inline “Generate hero image” button on a specific frontmatter field, you can’t build it on Sveltia today.
  • publish_mode: editorial_workflow — this is the one I had to find the hard way. Decap creates a cms/<collection>/<slug> branch + opens a PR per save, so nothing publishes without review. Sveltia silently ignores the config key. Every save in Sveltia commits straight to main. The only signal anything’s wrong is GitHub showing direct pushes instead of PRs.

That second one matters when the CMS technically has write access to a monorepo full of code, not just content. The PR-per-save model isn’t paranoia; it’s the only thing between a typo and an accidental commit to backend code. Decap honours it; Sveltia (today) doesn’t.

So why not just pick Decap? Because Sveltia has things Decap doesn’t:

  • The editor UX. Decap’s UI feels like 2018 React. Sveltia feels modern.
  • Best-in-class i18n editing — matters for the Spanish-English site I’m building next.
  • A bundle 3× lighter on first load (1.5 MB vs 5.4 MB on the wire).

And because they’re config-compatible, swapping from one to the other is cp admin/config.yml. So instead of picking blind, I’m running both side-by-side on real sites: Decap on heyeddsoftwares (the site you’re reading this on), Sveltia on bookverse. A few weeks of actual editing will produce a clearer winner than any feature comparison.

What the migration actually looked like

Coming from a Jekyll mindset, what surprised me most is how little there was to migrate:

  1. Content folders: untouched. .contents/articles/*.md stays exactly where Astro already expects it.
  2. Schemas: I copy-pasted the field shapes from src/content.config.ts (zod) into config.yml (CMS field definitions). 5 minutes per collection.
  3. Build/deploy: unchanged. The Astro deploy still rsyncs dist/ to nginx. The CMS deploy is separate — two static files copied to a /cms/ subpath of the same site.
  4. Auth: a tiny OAuth proxy as a Cloudflare Worker (free tier, 100k req/day) brokers GitHub login. Setup once, serves every CMS site I add later.

Total time from “no CMS” to “two CMSes editing real content end-to-end” was about a day, including the side-by-side experiment.

Compare that to migrating Jekyll content into a database-backed CMS: write an import script, validate the import, update Astro to read from the API instead of files, set up content-delivery caching, redeploy, hope nothing was lost in the conversion. Days of work, and ongoing dependency on a service.

Where I am now

Both CMSes are live and editing real content. I’ll write a follow-up when the side-by-side resolves. My current bias: Sveltia wins on UX, Decap wins on stability, and the call comes down to whether the missing Sveltia features land in 1.0 before I get tired of the workarounds.

But the broader question — “which CMS for a site I migrated from Jekyll or Gatsby” — has an unambiguous answer: stay file-based. Keystatic, Decap, or Sveltia. Pick one, point it at your existing content folders, you’re done.

The thing that made Jekyll worth using — your content lives in your repo, with the rest of your code, under your control — is the same thing that makes a git-based CMS the right successor. Everything else is just choosing between editors.

← All articles