July 31, 2026 · Steve Johnson
Adding a blog without letting the CMS own the deployment
I wanted a blog on this site. The obvious path was the CMS's own hosting: point it at a domain, deploy, done in a few minutes. I didn't take that path, and the reason is worth writing down because it's a pattern that shows up with almost any headless CMS you evaluate.
What the "easy" path actually does
The CMS I'm using, Letterstory, can spin up a fully hosted blog on its own infrastructure — its own rendering framework, its own deploy pipeline, a domain it registers and manages for you. That's genuinely useful in a lot of cases. It wasn't useful here, for two concrete reasons I found by reading the tool schema before writing any code:
- It can't attach a domain I already own. The tool that wires up a custom domain only registers new domains under the platform's own registrant. There's no operation for pointing it at a domain I already bought and manage elsewhere.
- Domains are capped. Even setting that aside, the account is scoped to a small number of managed domains, and the slots I have are already spent on other projects. A new hosted blog would need a slot that doesn't exist.
So "just deploy the blog on the CMS" was never actually on the table for this domain. Finding that out from the schema up front — rather than half-building it and hitting the wall later — is the whole point of checking first.
Splitting content from presentation
The fix is the one you'd reach for with any headless CMS: stop treating it as a hosting platform and start treating it as what it actually is — a content store with an API. Two read-only calls do all the work:
list_published— every published article in a collectionget_published— one article's full content by slug
Both return markdown regardless of the format you ask for, plus the metadata a blog page needs: title, summary, publish date, tags. I wrote a small server-only fetcher around those two calls, gated by an API key that never leaves the server, and two routes — a blog index and a post page — that pull that content into the site I already have. Same domain, same design system, same deploy pipeline. The CMS never touches routing, hosting, or rendering; it just answers "what's published" and "what does it say."
Markdown-to-HTML is one call to a markdown parser, rendered through a CSS class that matches the rest of the site's type scale instead of importing a second design language. The one wrinkle worth mentioning: the API's content includes its own leading title line, which duplicates the page's actual heading, since the page already renders the title from metadata — worth stripping before render if you don't want two headings for one title.
The general shape
Whenever a CMS's "one-click hosted" story doesn't fit your domain, your deploy pipeline, or your design system, this is usually the fallback, and it's usually fine: the content lives in the CMS, the presentation lives in your own app, and the two talk over a couple of read endpoints. You give up zero-config hosting. You keep the domain, the design, and the deploy pipeline you already have — which, if you already like the site you have, is the part that actually mattered.
This post is running on exactly that setup.