The short version
This site has no CMS. Page content lives as MDX and JSON files in Git, and Astro Content Collections validate the configured fields at build time. That removes the CMS content API, database and editor accounts from this setup, but dependencies, hosting and access control still need maintenance. AI agents can prepare edits with ordinary file operations, and Git makes those changes reviewable. Schemas do not fact-check prose or enforce human approval. Here is how the architecture works and when a CMS is still the better choice.
This website has no CMS. No Storyblok, no WordPress, no database with posts. Everything you read lives as MDX and JSON files in a Git repository, and Astro Content Collections validate the configured fields against schemas on each build. This article is such a file itself: frontmatter at the top, typed block components below.
Why would you want a website without a CMS? For a static site with a small technical team, a CMS can add more work than it removes: maintenance, access control and another system between “text ready” and “page live”. When I made the trade-off for this site, most CMS features went unused. Git conventions covered the content management I needed and gave the AI agents a familiar way to prepare changes.
In this article I explain how I approached it: the role Content Collections play, how the content in Git is organized, what it got us and when you are still better off choosing a CMS.
Why I dropped the CMS
Before the summer of 2026, this site ran on Astro with Storyblok. A solid combination, technically clean, and a stack I still use for client projects. But for this site, the friction kept growing.
For this site, bringing a CMS meant arranging a whole series of things around the content. A space with components and content models to keep in sync with the code. API calls in the build that depended on the CMS being available. Accounts and permissions for everyone who wanted to change something. Webhooks or rebuilds to trigger publication. And a second place where content lived: the repository held the code, the CMS held the content, and every change had to be understood in both worlds.
A workflow already built around files
The question that tipped the scale was simple: who actually works with this content? The answer: me and the team, plus the AI agents that do the preparatory work. This content workflow already used Git; a visual editor was not a requirement. The CMS added an interface I did not need for these tasks.
On top of that, the agents needed access to the CMS to change content. API credentials, an MCP server or another client, rate limits and draft workflows: all solvable things, but all extra moving parts. Editing checked-out files removes that CMS-specific integration. Repository permissions, deployment credentials and the AI tool itself still need to be managed and secured.
The core of the switch
A CMS can give editors a dashboard, permissions and publishing workflows. For this site’s technical team, those features did not justify a separate content system. A Git repository with typed content was the more direct fit, not a guarantee of better security or faster pages.
What Astro Content Collections are (and are not)
Astro Content Collections are the framework’s built-in content layer. They can load local files, remote sources or live data. This project uses local files and build-time validation: pages and articles as MDX, and datasets, case metrics, people and settings as JSON. Those are the six collections; using Astro does not require this particular setup.
This is the article collection configuration in this project, with the other collections omitted:
import { defineCollection, reference } from 'astro:content';
import { glob } from 'astro/loaders';
import { articleFrontmatterSchema } from './content/schemas/article';
const articles = defineCollection({
loader: glob({ pattern: '**/*.mdx', base: './src/content/articles' }),
schema: articleFrontmatterSchema.safeExtend({
author: reference('people').optional(),
}).superRefine((article, context) => {
if (article.articleType !== 'glossary' && !article.author) {
context.addIssue({
code: 'custom',
path: ['author'],
message: 'blog and case articles must include an author',
});
}
}),
});
// The full configuration also registers the people collection.
export const collections = { articles /*, pages, datasets, caseMetrics, people, settings */ };What the schema checks
The schema is a Zod definition that pins down which fields an article may and must have: title, route, publication date, author, category, tags, summary, FAQ items. If a required frontmatter field is missing or a field name is not allowed by the strict schema, the build fails with an error that names the file and the field. For your visitors nothing changes: the output is plain HTML.
So what it is: a contract between your content and your templates. Every article the template reads has passed the configured field checks. The same holds for the JSON datasets handed to cards and components. Validation only covers rules that have been defined: this project’s article schema requires a nonempty blog summary but does not set a maximum summary length. It does not fact-check prose or enforce human approval.
A content layer, not an editor
And what it is not: a CMS. This local-file setup has no CMS database, visual editor or CMS API token. Content Collections do not replace the editor experience of Storyblok or WordPress; that experience simply does not exist here. Preview environments and access controls can still be configured separately. Anyone who wants to drag and shuffle content in a familiar dashboard every day will miss it immediately. More on that in the section about when to choose a CMS anyway.
For the broader context first: what a CMS is and how a headless CMS works are explained separately in the knowledge base.
How our architecture looks: MDX and JSON in Git
The entire content structure of the site lives in one repository. This is the organization in short:
src/content/
├── pages/ # landing pages and hub pages (MDX)
│ ├── nl/ # Dutch-language pages
│ └── en/ # English pages
└── articles/
├── nl/
│ ├── blog/ # blogs
│ ├── case/ # case studies
│ └── begrippen/ # glossary terms
└── en/
├── blog/ # blogs
├── case/ # case studies
└── glossary/ # glossary terms(Datasets, case metrics, people and settings live as JSON alongside this tree; the structure above shows the MDX side.)
Every MDX file starts with frontmatter that must satisfy its schema. The frontmatter of this article contains, among other things, the route, the author, the summary for “the short version”, the FAQ at the bottom of the page and the reference to the image above. Below that frontmatter sits the body: regular Markdown headings inside typed section components. Internal links are regular links; build-output checks enforce the URL convention without trailing slashes.
Publishing and translations
That is the core of what makes Git useful here. Every committed content change has a diff: you see which line in which file changed, when, by whom and why in the commit message. A push to the main branch triggers Vercel to build and deploy; a local commit alone does not publish. Rolling back means reverting the change and deploying the result. There is no second system to keep in sync and no version in a CMS that can drift from the code that renders it.
That structure also keeps the language versions connected. The site is bilingual, and the English counterparts are linked to the Dutch pages through a fixed pair registry. Because those pairs live in the repository, the build checks can verify that every link points to a real route and that both sides confirm each other’s existence.
| Criterion | Classic CMS | API-first headless CMS | This site's Git workflow |
|---|---|---|---|
| Where content lives | CMS database | Database behind an API | Files in the repository |
| Who edits content | Editors in the dashboard | Editors in the dashboard | Anyone with repository write access |
| Validation | CMS field and server checks | CMS schema; build checks possible | Strict schemas and content checks |
| Publishing | Draft and publish workflow | Publish; rebuild if static | Push to main; successful deploy |
| Version history | Revisions in the CMS | Revisions in the CMS | Full diff per committed change |
| Extra maintenance | Core, plugins, database | CMS/API integration and accounts | Dependencies, CI, hosting and access |
| Runtime dependencies | Usually a server and database | None for prebuilt pages; API for runtime fetching | Static hosting; no CMS runtime |
| AI agent access | Authenticated tools or API | Authenticated CLI, API or MCP | File operations; repository and deploy permissions |
The table compares common setups, not limits of each category. A Git-based CMS adds an editing interface over files and can also be headless. This site uses neither that editor nor an API-first CMS. The last row explains why that direct-file approach fits the agents working on this project.
Why AI agents benefit: Git as a workplace
AI coding agents can read instruction files, explore a project, run commands and edit files. The GitHub article on writing agent instructions recommends concrete commands, examples and boundaries. That supports explicit project guidance; it is not a benchmark proving that Git always beats a CMS.
The AI agent Hermes works with the files and schemas in this repository. A CMS needs an authenticated client, which can be a CLI, a direct API integration or an MCP server. Local edits avoid that CMS-specific access layer. CloudCannon argues for this file-based approach too, but it sells a Git-based CMS. I treat that as a vendor’s perspective, not independent proof of lower AI costs. Reading a local file avoids a CMS API request; text sent to a model still consumes tokens, and caching or selective API queries can reduce remote work.
What file-based editing changes
The practical benefits are specific:
- Reading a file needs no CMS API request. Frontmatter, structure and content are available together in the checked-out MDX file.
- Writing is an ordinary file operation. Rewriting a section, adding an FAQ item or updating internal links uses the same tools as code editing.
- Every committed change has a diff. A reviewer can inspect it alongside the template and schema changes rather than reconstructing the change from a separate CMS log.
- The build checks the configured content contract. An invalid date or missing required field stops the build; plausible but false prose can still pass. For the wider process, read the blog workflow with AI.
People set the scope and remain responsible for publication. Authorized automation can publish after checks; a separate human review before every push is not guaranteed by Git or by a schema. Diffs make review possible, but permissions and required checks determine what can actually reach production. An agent with broad write or deploy access can do damage in either setup. Keep those rights limited rather than treating an instruction file as a security boundary.
What it got us: measuring, not claiming
Numbers about your own migration only mean something if you actually measure them. I therefore treat this site as an ongoing case study: monthly PageSpeed measurements and monthly Search Console data, publicly visible on the Straffe Sites case page.
As of September 3, 2026, the site’s mobile Performance score was 100/100, with an LCP of 1.4 seconds. Across the twelve other case sites in the series, the median best September score through that date was 99/100 mobile Performance. The fastest measured LCP in September through that date was 937 milliseconds. These are PageSpeed Insights lab measurements of production URLs, not field data or a controlled before-and-after test of removing a CMS.
What those numbers do not prove
Those scores do not establish that removing the CMS made the site faster. The lightweight technical foundation comes from static rendering, limited JavaScript and the assets delivered to the browser. A headless CMS can feed the same static output at build time. Removing its API from the build reduces a build-time dependency; it does not automatically improve visitor performance.
The operational change is simpler to describe: this site’s content workflow no longer needs a CMS service, CMS editor accounts or a CMS integration to maintain. Framework dependencies, the build pipeline, hosting and credentials still need attention. There is one less system, not zero maintenance.
When should you choose a CMS anyway?
This approach is not a law. It fits a specific situation, and it is honest to name that boundary.
Choose a CMS if your team does not work in Git. A visual editor, draft statuses, permissions and publishing flows: those are exactly the problems CMS platforms are built for, and they solve them well. For many companies with a marketing team publishing weekly, a dashboard is useful. In those situations I also build solutions with a CMS, such as headless with Storyblok, or a Git-based CMS with a visual editor that writes to Git under the hood: the editor experience stays, the benefits of files stay. If you hesitate between both routes, I describe the commercial side of such an architecture on the page about having a headless website built.
Editorial features are worth keeping
Also choose a CMS if your content structure changes often and quickly because of people outside the development team. A dashboard can make field management easier, although frontend templates may still need developer changes. In this approach a new content type is a schema and template change: development work.
A CMS can also provide built-in media libraries with user rights, publication scheduling, multilingual setups with per-field translation workflows, or integrations with other systems that run through the CMS. You can build versions of those features around Git, but then you are building a mini-CMS yourself, which is precisely what I wanted to avoid.
The question is who works with your content day to day. If that is a technical team that already lives in Git and uses AI agents, content in Git can be the more direct route. If that is an editorial team of non-technical people, a CMS can be the right tool and there is nothing wrong with that choice. To compare architectures side by side, read what a headless CMS is.
Not sure which route fits your team and plans? A short conversation helps more than reading another article. Discuss your project. And if you first want to know who you would be talking to? The page about this freelance web developer describes how I keep technology, speed and search visibility on a single track.

