Why We Built a CMS Instead of Using One
FolioKit started as a question: could Angular SSR carry a real production blog? The answer became the blog you're reading right now.
There's a moment every developer knows. You're evaluating tools for a new project, tabs open, docs half-read, and somewhere around the third "getting started" guide you think: I could just build this. Usually that's ego talking. Occasionally it's instinct. With FolioKit, it turned out to be both — and it led somewhere worth writing about.
The original motivation wasn't frustration with the CMS landscape. It was a more specific technical question: could Angular's server-side rendering hold up as the backbone of a real, production-grade blog? Not a demo. Not a tutorial repo with three hardcoded posts. A CMS with an admin, a public blog, scheduling, SEO, embedded media, and a design system coherent enough that readers never notice the scaffolding behind it. Angular SSR had matured significantly, and the honest answer was that most public examples weren't testing it seriously. We wanted to test it seriously.
WordPress was the first thing we looked at — not because we expected it to be the answer, but because it's still where most content-first projects begin. It's capable, battle-tested, and has an ecosystem that dwarfs everything else in the space. But it's also built on a fundamentally different set of assumptions than a modern TypeScript monorepo. The data model, the plugin architecture, the theming system — all of it reflects a web that predates the component model by a decade. It wasn't a bad tool. It was the wrong mental model for what we were trying to prove.
So we built instead.
FolioKit is an Angular 21 CMS toolkit — a monorepo with a public SSR blog, an auth-gated admin, a docs app, and a suite of published Angular libraries that wire them all together. The stack is deliberately opinionated: Angular standalone components, Firebase for everything persistence-related, NgRx signals for state, Angular Material 3 for interactive components, and a design token system that makes theming a matter of CSS custom property overrides rather than template surgery. There are no NgModules. There is no REST API layer to maintain. Posts live in Firestore, media in Cloud Storage, and the whole thing deploys to Firebase Hosting across three subdomains from a single Nx workspace.
The admin is where most of the architectural thinking lives. A split-pane editor with tabs for content, media, metadata, and SEO — all state managed in a signal store with no prop drilling anywhere in the component tree. Autosave on drafts with a two-second debounce. An unsaved-changes guard on navigation. An embedded media system where every image gets a stable token that you reference in Markdown, so moving or replacing a file never breaks a published post. These aren't exotic features. They're the things you notice are missing the first time you try to do serious editorial work in a tool that wasn't designed for it.
The design system reflects the same priorities. Playfair Display for headings — because editorial credibility is partly typographic. DM Mono for metadata and labels — because a CMS has a lot of metadata and it should feel considered, not bolted on. A single brand accent in amber-gold, a full ink scale for hierarchy, and semantic tokens that invert cleanly between light and dark without a single hardcoded color in any component. The theme marketplace — where site owners can purchase seasonal and curated themes that apply to both the public blog and the admin simultaneously — is built on the same token contract. Every theme is five to ten CSS custom property overrides served from Cloud Storage. No client bundles, no build steps.
But the thing we keep coming back to is simpler than any of that: this blog runs on FolioKit. The post you're reading was written in the admin at admin.foliokitcms.com, scheduled, tagged, given a thumbnail, and published to this page via Angular SSR with Firebase Admin SDK handling the server-side data fetch. The design system documented at foliokitcms.com is the same one rendering these words. The libraries published to npm under @foliokit are the ones the blog app actually imports. There's no demo environment where things work better than in production. Production is the demo.
That's the standard we're holding ourselves to. Not "good enough for a side project" but good enough that a developer evaluating FolioKit for their own blog can look at this one and make a judgment based on a real artifact, not a marketing page.
More on how it's built — and the decisions that didn't survive contact with reality — in the weeks ahead.