Sveltia CMS for 11ty: The Editorial Interface the Generator Lacks

A Git-based CMS as one HTML file and a script tag: what Sveltia CMS delivers for an 11ty blog, how to self-host it without a CDN — and why two pages of its own documentation disagree about file paths.

by ·

Two days ago I wrote a paragraph that has been nagging at me ever since:

"Editorial teams without a terminal. 11ty assumes Git, a command line and an editor. For colleagues who want to write a post and click 'Publish', that is the wrong shape."

The sentence is true, and it even pointed the right way: Git-based editing interfaces and Build Awesome Pro appear two lines later in the original. I just named them without going to look. As advice the paragraph therefore stops exactly where things get interesting — which is precisely what I hold against other articles.

So I went and looked at what actually moves that limit. The candidate is called Sveltia CMS, and I took it seriously: checked the documentation against the source, measured the shipped package, and wrote the configuration this knowledge base would need, then validated it against the official JSON schema. What I did not do: put it into production. So where I measure, I say so; where I judge, likewise.

The result up front, so you do not have to scroll: it is a remarkably good piece of software, and the first serious obstacle was not the CMS. It was my own directory structure.

What Sveltia CMS is

A Git-based headless CMS. Its own description is confident and, as far as I can verify, accurate:

"Sveltia CMS is a leading Git-based headless CMS for Jamstack sites. It's open source, free, and a complete modern rewrite of Netlify CMS, now known as Decap CMS."

"Git-based" is the decisive word here, and it means something different from a classic CMS. There is no database and no server. The content is and remains Markdown files with YAML front matter in your repository. The CMS is a single-page application that runs in the browser, attaches itself to your repository through the GitHub API, and makes a commit when you save. After that your normal build runs.

Put differently: it is a form over your files. Nothing more, and that is the whole trick.

Behind the project stands one person: Kohei Yoshino from Toronto, by his own account a UX engineer with over twenty years of web experience and a former long-time localizer at Mozilla. The licence is MIT. It is built with Svelte 5 — deliberately not SvelteKit, and the reasoning says a lot about the priorities:

"It's not a SvelteKit application, as we need to maintain its architecture as a single-file JavaScript bundle to ensure compatibility with Netlify/Decap CMS."

One bundle, one file, one script tag. I measured what actually goes over the wire — version 0.197.1, fetched from the official CDN on 24 August 2026:

Value Measured
dist/sveltia-cms.js raw 1,969,605 bytes (1.88 MiB)
the same, gzip-compressed 601,579 bytes (588 KiB) with gzip -9; over the wire unpkg sends about 601,800
CSS files in the package 0
Locale files 26, de.json at 46,419 bytes

Just under 600 KiB for a complete editorial interface is fine — and it only ever hits the editors, never your site's visitors. The zero on CSS files is not an accident but a design decision I will come back to.

The backstory worth knowing

To explain why this project exists I have to go back a little — and straighten out a point I regularly see misrepresented.

In the beginning there was Netlify CMS, for years the default answer to "I want a form over my Jekyll blog". At some point development stalled. Sveltia CMS came about, by its own account, "in November 2022, when the progress of Netlify CMS was stalled for more than six months". In February 2023 a different team took over the original and renamed it Decap CMS — with the remarkably candid explanation: "We took this step because we didn't like that this awesome project was slowly dying, and we wanted to ensure that it would continue to be supported and improved."

Two successors, one root. Both are alive, and contrary to some tellings Decap is not dead: version 3.15.1 dates from 24 July 2026, there were commits last week, and in May 2026 a commercial add-on called "Decap Turbo" was announced. Anyone writing Decap off today is wrong.

And now the point almost everyone conflates: Netlify Identity is not deprecated — Git Gateway is. Netlify had announced Identity's deprecation and then explicitly reversed it on 19 February 2026: "Netlify Identity will continue as a supported authentication option on Netlify." The component that really is dying is Git Gateway, and that is what the classic Netlify/Decap CMS login depends on. The Netlify docs are unambiguous:

"Git Gateway is deprecated. While Git Gateway continues to function for sites that currently have it enabled, new Git Gateway configurations are not recommended."

That is not hair-splitting, it is a planning basis: if you are setting up a new Git CMS installation today, do not start down the Git Gateway road at all. Sveltia CMS consistently does not support it — and, just as consistently, does not support the Netlify Identity widget either, "it's not useful without Git Gateway".

Two files and you are in

Installation is the part where, on first reading, I assumed I had skipped a page. It really is two files in your static directory. First, admin/index.html, unchanged from the official guide:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="robots" content="noindex" />
    <title>Sveltia CMS</title>
  </head>
  <body>
    <script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
  </body>
</html>

Second, admin/config.yml next to it — the file is loaded automatically from the same directory, with no path to configure.

In an 11ty project both belong in your static directory; in this one that would be src/static/, which is copied verbatim into the output root. The Sveltia documentation lists Eleventy explicitly in its table of static folders — and elsewhere even names 11ty's development port, 8080. The project knows who uses it.

Two things you should not do are called out explicitly in the guide — and the first one made me grin:

"Some AI agents, namely Claude, include a stylesheet <link> tag in Sveltia CMS setups, apparently due to confusion with Static CMS, a now-discontinued fork of Netlify CMS. However, Sveltia CMS does not require any additional CSS files, as all the necessary styles are bundled within the JavaScript file."

That is the zero in my table above: I queried the published package's file list — 37 files, not a single CSS file. So the warning is justified, and it is a neat little lesson in how a misconception propagates through training data. The second pointer: no type="module" on the script tag. An ES module does ship with the package, but it is not what the CDN snippet loads — and the attribute can cause unexpected behaviour when you use the JavaScript API.

The schema that found a bug for me

There is a trick in the configuration step I know from hardly any other project: a JSON schema is published with every release. One line at the top of your config, and your editor completes and validates as you type:

# yaml-language-server: $schema=https://unpkg.com/@sveltia/cms/schema/sveltia-cms.json

I did not take that on faith, I checked: the file is there, 294,117 bytes, HTTP 200. And then I validated my own configuration against it — with a result I had not expected. One field was wrong, this one:

- { name: kind, label: Type, widget: hidden, default: article, i18n: duplicate }

The schema rejects it — but not where I had assumed. The hidden widget knows exactly four keys: name, widget, default and i18n. There is no label among them, because an invisible field has nothing to caption. i18n: duplicate, by contrast, is explicitly allowed and is in fact right here — it copies the default locale's value into all the others. So only the caption was wrong, and you do not arrive at that yourself while busy giving twenty fields their labels. The correct version:

- { name: kind, widget: hidden, default: article, i18n: duplicate }

A configuration bug caught before the application had ever started once. That is exactly the kind of check I wish more projects offered, and for me one of the strongest points overall: a CMS whose configuration is machine-checkable moves an entire class of errors out of runtime and into the editor.

The test against my own project

Now the part that hurts, and the reason this article does not end with a recommendation.

This knowledge base is bilingual. German is the default and lives under src/content/…, English mirrors everything under src/content/en/…. That was the very first architectural decision of this project, and it follows my main site.

Multilingual content is not a bolted-on extra in Sveltia CMS, it is the founding reason:

"Sveltia CMS was originally built for @kyoshino's Japanese clients, who needed a CMS that could handle multilingual content efficiently. The maintainer is a former long-time localizer for Mozilla and lives in the most diverse city in the world where 150+ languages are spoken."

You can tell. Five structures for multilingual content are on offer, and translated versions are linked automatically: in the editor you see one entry with several locale tabs, not two separate files. That is exactly what I wanted. So I laid the documented path patterns side by side:

Structure Resulting path
single_file /<folder>/<path>.<extension>
single_file_default_root /<folder>/<path>.<extension> (like single_file, except the default locale's fields sit at the top level)
multiple_files /<folder>/<path>.<locale>.<extension>
multiple_folders /<folder>/<locale>/<path>.<extension>
multiple_root_folders /<locale>/<folder>/<path>.<extension>

And then the penny dropped — the wrong one. My structure is src/content/en/blog/article.md, so the locale sits in the middle, between content/ and the section folder. Set folder: src/content/blog and multiple_folders produces src/content/blog/en/article.md, while multiple_root_folders produces en/src/content/blog/article.md. Neither is my structure. I had already written the paragraph in which the project founders on my 2026 directory decision.

The mistake was mine. I had taken <folder> to be the whole path, and it is not. The collection documentation says so plainly, just in a different place: folder is the base, and path may contain slashes ("It can contain slashes to create a nested folder structure", default {{slug}}). The locale segment is not inserted between section and file — it goes between folder and path. Which means you can put the cut wherever you like:

folder: src/content      # the base
path: blog/{{slug}}      # the rest — slashes allowed

Work it through: multiple_folders yields src/content/de/blog/article.md and src/content/en/blog/article.md. The English side then matches exactly. Only my German files sit without a de/ directly under src/content/blog/ — and that is precisely what omit_default_locale_from_file_path: true is for.

Where the documentation contradicts itself

And here it got interesting, because at this point the documentation says two different things. For multiple_folders with omit_default_locale_from_file_path set, the entry-collections page states:

/<folder>/<path>.<extension>          # default locale
/<locale>/<folder>/<path>.<extension> # other locales

By that table the locale would jump to the front for every non-default locale, right to the start of the path — turning src/content/en/blog/ into en/src/content/blog/. That would put me back where I started.

But the project's own i18n page says something else at the very same point:

/<folder>/<path>.<extension>          # default locale
/<folder>/<locale>/<path>.<extension> # other locales

Two pages of the same documentation, two different paths. That is not settled by reading but by looking. In dist/sveltia-cms.mjs the path construction is a plain switch; here with the names restored from the minified bundle:

switch (structure) {
  case "multiple_folders":
    return omitLocale ? `${basePath}/${path}.${ext}`
                      : `${basePath}/${locale}/${path}.${ext}`;
  case "multiple_folders_i18n_root":
  case "multiple_root_folders":
    return omitLocale ? `${basePath}/${path}.${ext}`
                      : `${locale}/${basePath}/${path}.${ext}`;
  // …
}

There it is in black and white: with multiple_folders the locale segment stays behind the base, and omit_default_locale_from_file_path merely drops it for the default locale — it does not move it. Only multiple_root_folders pulls it to the front. The expression the CMS uses to recognise existing files is built the same way: there the locale segment simply becomes optional ((?:(?<locale>en)\/)?), not relocated.

So the case is clear: the i18n page is right and the collections page has a bug — the line from the multiple_root_folders block has evidently slipped one paragraph too far up. This is not a grey area and not undocumented behaviour, it is a typo on one of two documentation pages. It still deserves reporting, because it costs exactly the decision I nearly got wrong here.

For my project that means it fits. This configuration validates against the official schema with zero errors

i18n:
  structure: multiple_folders
  locales: [de, en]
  default_locale: de
  omit_default_locale_from_file_path: true

collections:
  - name: blog
    label: Blog
    label_singular: Beitrag
    folder: src/content
    path: blog/{{slug}}
    create: true
    i18n: true
    fields:
      - { name: title, label: Titel, widget: string, i18n: true }
      - { name: description, label: Beschreibung, widget: text, i18n: true }
      - { name: translationKey, label: Übersetzungsschlüssel, widget: string, i18n: duplicate }
      - { name: kind, widget: hidden, default: article, i18n: duplicate }
      - { name: date, label: Datum, widget: datetime, i18n: duplicate }
      - name: tags
        label: Themen
        widget: select
        multiple: true
        i18n: duplicate
        options: [eleventy, ssg, cms, node, npm, markdown, security, accessibility, seo, geo]
      - { name: body, label: Inhalt, widget: markdown, i18n: true }

— and the path logic, worked through, gives src/content/blog/article.md for German and src/content/en/blog/article.md for English. Exactly the tree that has been sitting here since day one, without a single file moving. Automatic linking included: both language versions would be one entry with two tabs.

One caveat belongs with that, and I do not want to play it down: I derived this from the schema, the docs and the source, not from a running installation pointed at my repository. Three agreeing pieces of evidence are not a deployment. Before a real editorial launch I would try it on a throwaway branch, and so should you.

If you would still rather play it safe, there is a conservative way out: two separate collections with folder: src/content/blog and folder: src/content/en/blog and no i18n block at all. That is guaranteed to work, but it costs the automatic linking — the translationKey that holds my German and English versions together becomes a field somebody has to fill in correctly by hand again.

Incidentally, the select field with a fixed list of options is the small joy in this configuration. This site keeps its topic tags in a controlled vocabulary, and an invented tag renders here as a bare slug instead of a proper label. As a dropdown in the editor that simply cannot happen any more. A rule that until now lived in a documentation file becomes one the tool enforces.

What I take from the afternoon is nonetheless the lesson I had already written down before the finding flipped — it now holds twice over: the moment a Git-based CMS looks at your repository, your directory tree becomes an interface. It always was one, nobody just noticed, because until then only the generator ever looked at it, and a generator reads anything. A CMS has opinions. And the second half of the lesson I handed to myself: I came within an inch of publishing this article with a wrong conclusion, because I read one documentation table — the faulty one, of course — instead of comparing two pages and working it out when they disagreed. If you are sitting in front of a bilingual 11ty project and have even an inkling that somebody else might write in it one day: look at the five structures before you create the first directory — and when in doubt, check what the tool does, not just what it says about itself.

What else convinced me

Beyond my special case, the feature list is genuinely impressive, and I will only name what I would actually need for a blog like this one.

Switching from Decap really is one line. The migration page shows it as a diff:

-<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
+<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>

The project stays pleasingly honest about it and does not overpromise: "In some casual use cases, Sveltia CMS can be used as a drop-in replacement for Netlify/Decap CMS with just a one-line code update." And two paragraphs later: "However, 100% feature parity is never planned, and some features are still missing or will not be added due to deprecation and other factors."

Image optimisation at upload time. Raster images are converted to WebP in the browser, SVGs optimised, all through a few lines of configuration:

media_libraries:
  default:
    config:
      transformations:
        raster_image:
          format: webp
          quality: 85
          width: 2048
        svg:
          optimize: true

Anyone who has ever cleaned up after an editorial team that uploads 6-megapixel phone photos straight into the CMS knows what that is worth. And it happens in the browser, before the commit exists — so the enormous file never enters the Git history, where you can never get rid of it again.

Editorial approval as pull requests. With publish_mode: editorial_workflow every draft gets its own branch following the pattern cms/<collection>/<slug> and an open pull request; publishing means merging. That is the most elegant solution to this problem I know, because it invents no new concept but uses one that is there anyway — and it keeps the full Git toolbox available to you as a developer during review.

Commits are signed. Commits created through the GitHub API are automatically GPG-signed and marked "verified".

The content security policy gets easier, not harder. Unlike Decap, Sveltia CMS needs neither unsafe-eval nor unsafe-inline in script-src. One detail for the non-English case: a localised interface loads its locale file from the CDN at runtime — the 46 KB de.json I measured above. For that you need connect-src https://unpkg.com in your policy. Not dramatic, but exactly the line you forget on the first attempt and then spend an hour hunting.

The interface is available in German, and in 26 languages in total, with automatic browser-language detection. For the use case from my opening paragraph — colleagues who do not want a terminal — that is not a luxury but half the battle.

Accessibility: claim and current state

This is my subject, so I look more closely here — and phrase it more carefully than the marketing would.

The claim is explicit: "Sveltia CMS is built with accessibility as a core principle." It names full keyboard operation including alternatives to drag-and-drop, "Full WAI-ARIA support for screen readers like NVDA and VoiceOver", announced page changes, sufficient contrast, links underlined by default, and respected prefers-reduced-motion and prefers-reduced-transparency settings. The interface components come from an in-house library built explicitly "for optimal keyboard usability without compromising accessibility".

And now the context that belongs with it. The project itself says:

"We'll conduct an accessibility self-audit and address any issues before the 1.0 release to make sure Sveltia CMS meets the WCAG 2.2 standard."

In plain terms: there is no published audit today — neither external nor their own. The audit is a roadmap item for version 1.0. Support for prefers-contrast is still missing. If you have to deploy an editorial interface in an environment where accessibility legislation applies, you have a commitment and a timetable in hand, but not evidence. That is still more than most CMS interfaces offer — it is just not a box you can tick in a procurement document.

To be fair: editorial interfaces often fall outside the same obligations as the public website. But if your editorial team includes people with disabilities — and it should — this is a practical question, not a legal one.

The local route, and why it snags for me

There is a second operating mode that needs no service at all: "Work with Local Repository". You open the interface, pick your project directory, and the CMS edits the files directly on your disk — via the browser's File System Access API, with no helper server. Decap needs a proxy process for this; Sveltia explicitly refuses one: "For security and performance reasons, we don't support netlify-cms-proxy-server or decap-server."

Elegant. And so far unusable for me, for two documented reasons.

First, the File System Access API only works in Chromium-based browsers. Firefox and Safari are out.

Second, and this one hits me directly:

"If you're using Windows Subsystem for Linux (WSL), you may get an error saying "Can't open this folder because it contains system files." This is due to a limitation in the browser, and you can try some workarounds mentioned in this issue and this thread."

I develop under WSL2. My projects live in the Linux file system, the browser runs on Windows. Exactly the constellation the paragraph describes. There are workarounds in the linked discussions, but "there are workarounds" is not a sentence I would leave an editorial team alone with.

And even if it did run, one restriction would remain that you have to know about: the local mode performs no Git operations. "You have to manually fetch, pull, commit and push all changes using a Git client." As a preview mode for developers that is excellent; as an editorial tool for non-technical people it is the opposite of what you are looking for.

So for the actual use case the GitHub route remains. And it is more convenient than I expected: for yourself, a personal access token is enough, with no configuration change at all. Only when people without GitHub accounts need to sign in do you need an OAuth client — the project ships its own Cloudflare Workers script for that, whose README carries a bold callout right under the heading: "In most cases, you don't need this authenticator."

The honest downsides

A fan article without limits is advertising, here as in the last one. So, in order.

It is beta, and that sits in large type above the guide. "Sveltia CMS is still in beta. Although it's already being used in production by many users, there might still be breaking changes before the stable 1.0 release." The current version is 0.197.1. Version 1.0 is targeted for "late 2026", with the caveat "this date may change".

The release frequency is unusual, and it cuts both ways. The project says so itself: "usually multiple times per week or even multiple times per day." Counted: five versions in four days, ten releases in eight days, and 0.197.1 landed on the day I wrote this article. For a one-person operation that is a remarkable cadence. But for you it also means: the default script tag always loads the newest version — including possible breaking changes in a minor release, because before 1.0 semantic versioning explicitly allows them. If stable editorial work matters more to you than every new feature, pin the version in the URL.

A script tag without a safety net

Which brings me to a point I cannot walk past as someone who writes about npm security.

Look at that recommended script tag again: it loads an unversioned file from a third-party CDN with no integrity check. Every visit to your editorial interface fetches the newest bundle — 1.88 MiB of foreign JavaScript that, at that moment, has full access to a window holding your GitHub token. This is exactly the attack surface I take so seriously at build time, just one storey down: it is not at npm ci, it is at every login.

I do not want to dramatise this. unpkg is well established, the package is published with npm provenance, and the admin page carries noindex. But it is a default that two attributes improve considerably — and I checked that it actually works:

<script
  src="https://unpkg.com/@sveltia/cms@0.197.1/dist/sveltia-cms.js"
  integrity="sha384-Ey0tcaM4hcMi78saAC2mMD/+2UoxzNc3iX/8n9w4Q34yqosJHst5cU00ozCzDd2p"
  crossorigin="anonymous"
></script>

Three preconditions had to hold, and all three do: unpkg sends access-control-allow-origin: *, sets cache-control: max-age=31536000 for the version-pinned URL — so the file is immutable — and the digest can be verified. I computed the sha384 value myself over the fetched file; as a cross-check I also computed the sha256 and compared it with the one unpkg publishes in its metadata and in the content-digest header — identical. The sha384 value above comes from my own calculation on 24 August 2026 and applies to 0.197.1 only — with every new version you have to recompute it, or the interface will not load at all.

And that is precisely why the project does not make it the default: for software that ships several times a week, a fixed hash would be a permanent maintenance chore. The trade-off is still yours, not the project's. For an editorial interface touched only every few months, a pinned version with a checksum is the right call — and you get the stability from the previous paragraph thrown in.

Self-hosting — and what stays on the CDN anyway

That script tag loads from someone else's network, and in Germany that is not a matter of taste but something you have to be able to answer for. Every visit to the editorial interface sends an IP address and user agent to unpkg and, as it turns out, to a second CDN as well. This is exactly the pattern that produced years of legal warnings over Google Fonts.

The proportionality first, because that tends to get skipped in these discussions: this is not about your visitors. Sveltia CMS runs only in the admin area, which only signed-in editors open; the public site stays static HTML without a single third-party request. So the group of affected people is small and known. Small does not mean irrelevant, though — your editors are data subjects under the GDPR too, and if you keep a record of processing activities, this connection belongs in it.

The good news: you do not have to use the CDN. The documentation names the route explicitly — install through a package manager instead of the script tag, then initialise the CMS manually through the JavaScript API:

npm install @sveltia/cms

The bundle then lives in your own repository, ships with your build, and comes from the same host as the rest of your site. Updating becomes your job, which the project documentation also points out — in exchange the runtime dependency on a foreign network disappears, and the Subresource Integrity question from the previous section resolves itself along with it.

The bad news: that does not remove the CDN entirely. I looked inside the shipped bundle, and there are hard-wired addresses in it:

What Where from
Modular dependencies https://unpkg.com/@sveltia/cms
Syntax highlighting (Shiki), lazy-loaded on demand https://unpkg.com/@shikijs, https://unpkg.com/@sveltia/ui
Three typefaces (Source Sans 3, Noto Mono, Material Symbols) https://cdn.jsdelivr.net/fontsource/…
Any interface language other than English https://unpkg.com (the de.json I measured)

The project describes this as an architectural choice of its own — "Dynamically loads additional dependencies from UNPKG rather than bundling everything into one large file" — and its example content security policy confirms it: script-src and connect-src there carry https://unpkg.com, plus font-src 'self' https://cdn.jsdelivr.net. I could not find a configuration option that redirects those addresses to your own host: the official JSON schema contains neither unpkg nor jsdelivr, and the CDN entries it does have concern external media storage only.

So anyone who genuinely needs zero third-party requests — a public authority, a hospital, a works council with a clear position — will not get there with the npm package alone. What remains: serve the fonts yourself and override them in CSS, mirror the lazy-loaded modules or do without them, and verify the result in the network tab rather than believing it. Doable, but work — and a good subject for an issue on the project, because a configurable CDN base would be a real selling point in the European market.

I want to stay honest here too: I have not run the npm variant myself. I read the addresses above out of the shipped bundle and held them against the project's own CSP recommendation — which of them actually fire in a self-hosted install is something to measure in the concrete case.

It is a one-person project, and it is closed to contributions. "At this point, the codebase still requires significant refactoring and improvements in test coverage, so pull requests from the community are not being accepted yet." In the 11ty article I wrote why I prefer paid full-time work on open source to volunteer burnout. That sentence holds here too, it just points the other way: Sveltia CMS funds itself through GitHub Sponsors. This is the case I described there as a risk — with the difference that the consequences of failure are milder for an editorial tool. If it stops tomorrow, your content still sits in your repository as Markdown. That is the entire point of this shape.

And now the punchline I got stuck on. I came here because of editorial teams. And then the guide says:

"Sveltia CMS does not officially support multi-user scenarios yet. Be cautious when multiple users are editing content simultaneously, as it may lead to merge conflicts or unintended overwrites."

For the case I named two days ago as a limit of 11ty — several people writing at the same time — that is not a footnote, it is the core. So the tool closes the gap for one editor, not for an editorial team. That is real progress and still not what I was looking for. In practice it can be defused: separate areas, agreed times, editorial workflow with separate branches. But that is organisation, not a feature.

Scale is a deliberate limit. The project answers the question about large installations with a clear no: "Sveltia CMS is primarily designed for small to medium-sized projects, such as personal blogs, portfolios, and small business websites." This knowledge base has 966 built pages. I am not sure which side of that line I am on, and I would have to try it rather than guess.

Small print worth taking with you: nested collections are still missing. Git LFS is unsupported on the GitHub backend. Bitbucket and Azure DevOps do not exist — for performance reasons, but with an explicit promise to support them once their APIs allow fetching multiple entries at once. Git Gateway will not exist in that form; for 1.0 a replacement of the project's own is announced instead, commits without a Git service account. The interface requires a secure context, so it only runs over HTTPS or localhost. A few defaults differ from Decap — filenames are not slugified automatically, empty optional fields are not omitted, Markdown uses soft rather than hard line breaks. And there is explicitly no free setup support: "Questions about installation or initial configuration may go unanswered." Whether this project copes with a path prefix — this site lives under /db/ — is addressed nowhere in the documentation. For me that is an open question, not a claim in either direction.

The field next door

So that you know the alternatives, briefly and without a ranking. All figures as of 24 August 2026:

Tool What it is Status
Sveltia CMS Rewrite of Netlify CMS, Svelte, CDN script 0.197.1, beta, very active
Decap CMS The renamed Netlify CMS, same shape 3.15.1 (24 Jul 2026), active
Tina CMS Git content plus visual editing, optional cloud 3.12.1 (24 Aug 2026)
Keystatic Schema in TypeScript, edits files in the repo 0.6.8 (20 Aug 2026)
Pages CMS GitHub repository as the only data source, hosted or self-run 2.1.8 (8 Jun 2026)
Front Matter CMS Runs entirely inside Visual Studio Code 10.12.0 (21 Aug 2026)
CloudCannon Commercial and hosted, names 11ty explicitly SaaS, no version

And then there is the in-house candidate. Build Awesome Pro — the commercial layer Font Awesome is building for 11ty — aims at exactly the same gap:

"Build Awesome Pro is a new service we're building to help anyone launch and maintain a web site—no installation required. It's a web site builder boasting visual editing and collaboration, zero lock-in (ever), while ultimately helping to fund continued Build Awesome (Eleventy) maintenance for the entire community."

The Kickstarter succeeded, with 838 backers according to the product page. Except the same page also says: "Build Awesome Pro Coming Soon!" There is no ship date, no package under the announced name exists on npm, and the editing API sketched in April 2026 sits under the heading "One Possible Editable API", illustrated by an example the post itself calls "hypothetical".

That is the situation, soberly stated: the official answer to my problem is announced and funded, but not here. Sveltia CMS is here. Anyone who has to decide today decides between a promise and a beta — and the beta has the advantage that you can try it in ten minutes without signing anything.

Beyond the obvious: a CMS you can take back off

The reason this shape excites me is not the feature list. It is a property that follows from it: you can remove this CMS again, and nothing happens.

Delete the two files from admin/, and your project is exactly what it was before: Markdown files with YAML front matter in a Git repository, built by 11ty. No migration, no export, no database dump, no recovering content from a proprietary field format. The CMS was never the place your content lived — it was a view onto it.

That is precisely the inversion of the bargain I entered into during my WordPress years. There my content belonged to the system in a very practical sense: in its tables, in its serialisation format, in the fields of its plugins. Getting out was work — which is why yesterday's article about @11ty/import exists on this blog at all. With a Git-based CMS there is no way out, because there was never a way in. The files were yours all along.

And one more thing fits together here that pleases me particularly as the operator of this site. Sveltia CMS ships a .md mirror of every documentation page, plus an llms.txt index and a long-form variant for language models — and it publishes an official agent skill for Claude Code, complete with a script that validates your configuration. That is exactly the experiment this knowledge base was built for: keeping content additionally available natively as Markdown, so AI systems can read it without noise. That a CMS project developed the same idea independently, and then even warns against outdated third-party skills, strikes me as a good sign — and as a small piece of evidence that the approach is not a private hobby-horse of mine.

Conclusion

Would I put Sveltia CMS on this site? Not yet — but for different reasons than I expected when I started writing. The one reason I did expect has fallen away: my directory structure fits, and it fits by the book. What remains is less dramatic. The local route fails on WSL, I write here alone anyway, and for a single author an editor and a commit remain the faster route. With 966 pages I am also beyond what the project recommends itself for. None of that is a charge against the tool — it is simply a different use case.

Would I recommend it for the case I described two days ago as a limit of 11ty? Yes, without hesitating. A manageable company site, a club blog, a portfolio — built with 11ty, maintained by somebody who never wants to see a terminal, with cleanly defined fields, image optimisation on upload and a localised interface: that is exactly the point where my sentence from two days ago was too pessimistic — and, as it turned out, so was my first draft of this article. I would pin the version, switch on the editorial workflow, and give myself two hours for the configuration beforehand. Then it holds.

What I am really taking away is something more fundamental, though. I wrote yesterday about a tool that brings content in, and today about one that makes it editable. Both work this undramatically only because there is nothing in between but files in a directory. That is not a technical nicety — that is the actual decision you make when you build a website. Everything else is replaceable. Your files are not.

Further reading