Open Source
The React Router boilerplate
that gets out of your way.
SSR-first, CMS-agnostic, and designed to ship. Clone, configure, and own your stack from day one.
What you get
Built for production from day one
Features
Everything you need, nothing you don't
CMS-agnostic by design
Swap from Sanity to Pocketbase — or any headless CMS — by changing one environment variable. Zero component changes required.
SSR on every request
React Router v7 in framework mode. Data loads server-side — no loading spinners, no client waterfalls, no hydration mismatches.
Design system built in
Tailwind v4 with dark mode, compact mode, accent colors, and radius scale — all toggled via html class flags with no JavaScript overhead.
Clean component architecture
Three layers: primitives → blocks → sections. Hard boundaries mean CMS editors never touch render internals.
Get started in minutes
Clone the repo and copy .env.example to .env. Set CMS_SOURCE=stub to run locally with no external dependencies — no API keys, no credentials, no setup required.
Architecture
Under the hood
SSR
Rendering strategy
Every page load goes server-side. No stale client cache, no rehydration flash.
4
Steps to a new section
Type → Component → Register → Data. The renderer handles the rest.
DataSource interface
getPage and listPages are the only two methods a CMS adapter needs. The rest of the app never knows which backend it's talking to.
Section registry
One entry maps a componentType string to a React component. Add it to the registry and it's immediately available in the renderer, stories, and documentation.
3
Component layers
Primitives, blocks, and sections with hard boundaries. Editors interact only with sections.
1
Catch-all route
$.tsx handles every CMS-driven page. No new route files needed for new content.
Philosophy
Designed to be replaced
A boilerplate you can outgrow is a good boilerplate.
Most boilerplates make choices for you and then make those choices hard to change. This one doesn't. The CMS, the design tokens, the section types — all of it is meant to be replaced, extended, or thrown out as your project evolves.
Core principles
- Front-to-back design — Components define their prop contracts. CMS schemas are generated from those contracts, not the other way around.
- Hard layer boundaries — Sections are the only layer the CMS touches. Blocks and primitives are render internals — stable, reusable, never exposed to editors.
- Authoritative normalizers — If a required field is missing, fix the CMS schema — not the component. Normalizers are the source of truth, not a defensive fallback layer.
- SSR by default — Every page is server-rendered. Client-side data fetching is opt-in, not the default pattern.