Blog post
I Did Not Need a CMS. I Needed a Reviewable Publishing System
Why I kept this blog's publishing system repo-native, with explicit state and handoff boundaries, instead of reaching for a CMS too early.
I Did Not Need a CMS. I Needed a Reviewable Publishing System
The decision was not “CMS or no CMS.” It was “which system should own a piece of writing before it becomes public?”
For this site, the answer needed to support a small, technical publishing workflow: write, revise, review, and publish work that should remain understandable months later. That is a narrower problem than operating a general editorial platform.
I compared three options: keep raw files, add a Git-backed editing layer, or adopt a fuller CMS. None was universally right. The decision came from the shape of the work and the cost I was willing to own.
The criteria
I cared about six things:
- one clear system of record;
- editorial state that could be inspected without reverse-engineering a UI;
- diffs that exposed substantive changes;
- a clean boundary between editorial machinery and the public site;
- a deliberate handoff into published content;
- an operating burden proportionate to the publication.
Editing comfort mattered, but it was not the hardest constraint. If the system made writing pleasant while hiding what was ready to publish, it would be optimizing the wrong part of the workflow.
The options
Raw files scored well on transparency and poorly on workflow guidance. A Git-backed editor improved the writing surface but still risked making the editorial process feel like a product before there was enough collaboration to justify one. A CMS offered scheduling, roles, and richer content operations, but those features arrive with another system to secure, migrate, observe, and keep synchronized with the site.
The question was not which option had the most capability. It was which option made the actual decisions easiest to review.
At the current scale, the repo-native option won: the repository remains the source of truth, editorial work happens outside the runtime surface, and the public site consumes only the explicit published artifact it expects.
Why explicit state beat a nicer editor
A publishing workflow has a state whether it names it or not. Draft, under review, ready, published, and archived are different claims about what may happen next.
If those claims live only in a dashboard, the interface becomes the place where the meaning of the content is hidden. A plain state transition is less comfortable, but easier to inspect, diff, validate, and explain to the next person—or the next agent—who touches the work.
The important boundary is not “file versus database.” It is implicit state versus explicit state.
This also keeps the public application small. Editorial notes, review metadata, and handoff logic do not need to become imports in the deployable site. The site can stay responsible for serving published content while the editorial system remains responsible for deciding what qualifies as published.
What this choice costs
The repo-native system is not free. It assumes comfort with version control. It gives up some collaborative editing polish. Scheduling and permissions are less turnkey. A non-technical author would reasonably experience those constraints as friction rather than virtue.
That residual cost is part of the decision, not an argument to hide it. I accepted it because the current workflow has one primary author, review is valuable in diffs, and operating another platform would create more surface than it removes.
The outer loop also remains mine: deciding what is worth publishing, what evidence is sufficient, and when a draft crosses the public boundary. Automation can validate and prepare that transition; it should not silently redefine it.
When I would change the decision
I would revisit the choice when the workflow acquired several regular authors, non-technical editors, complex scheduling, permissioned collaboration, or enough volume that repository operations became the bottleneck rather than the review surface.
Those are observable triggers. “A CMS feels more mature” is not one of them.
I did not reject a CMS. I rejected paying its coordination and operating cost before the work required it. For this site, the better system is the one that keeps intent, state, and handoff visible—and makes the decision easy to reverse when the constraints genuinely change.
Continue exploring
Follow the same line of thought through themes, tags, or a broader local search across the archive.
Keep following the thread.
I Could Build Faster. That Was Not the Hard Part.
AI makes software cheaper to explore and build, but not equally cheap to understand, secure, review, and own.
I Stopped Passing Tenant IDs Around My Application
Why tenant scope is an authority boundary, and how RequestContext makes multi-tenant trust explicit and enforceable.
Memory Is Not State
Agent memory is a scoped service layer, not runtime state owned by an agent instance.