There is a small category of CMS that skipped the database entirely, and it has been quietly correct about several things for over a decade.

Kirby has been going since around 2012. Statamic started about the same time and later rebuilt itself on Laravel. Grav came a couple of years after. All three store content as files in a directory tree, all three have paying customers, and none of them are toys.

The layout is the part I keep coming back to. In Kirby a page is a folder. The folder holds a text file with the content, and it holds that page's images. The URL structure follows the directory structure. You can open the content directory in a file manager and understand the entire site without launching anything.

That has consequences beyond tidiness.

Deleting a page deletes its images, because they were inside it. There is no orphaned media problem, which every database-backed CMS has and solves with a periodic cleanup job that nobody trusts to run unattended.

Moving a page is mv. Duplicating a section is cp -r. Backing up is tar. These are not clever features, they are the absence of a layer that would have made them into features.

Content is greppable. When someone asks which pages mention a discontinued product, the answer is a command rather than a query against a schema you have to remember.

And it composes with git, which means review, branches, blame and a history that a human can read.

The costs are real and the three of them handle it differently.

Listing and filtering means walking the tree. Kirby caches aggressively. Statamic added a Stache, its own index, precisely because the filesystem stops being fast enough somewhere in the low thousands of pages. That is the honest boundary of the approach: without an index it does not scale, and with an index you have taken on the job of keeping the index true.

Concurrent writes are a genuine gap. Two editors saving the same page over a filesystem is last write wins, and the second person's work is gone with no error and no record.

And the file becomes the schema. Front matter is whatever is in the file, so a typo in a key is a new key, and nothing notices.

The thing I find striking is how the category ages. A WordPress site from 2012 is a liability. A Kirby site from 2012 is a directory of Markdown that any tool can read, plus a PHP application you may or may not still want. The content survived the software, which is the property I care most about and the one that is hardest to retrofit.

If I were starting from scratch I would take the storage model and be much less relaxed about the index. The index is not an optimisation you add when it gets slow. It is the part that lets files be the truth without giving up querying, and it should be designed in from the beginning as something disposable and rebuildable rather than something precious.