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

3CMS sourcesSanity, Pocketbase, and stub — all behind a single DataSource interface.
0Client waterfallsReact Router v7 framework mode with full SSR on every request.
100%TypeScriptStrict mode throughout. Prop contracts drive CMS schemas, not the reverse.
ThemesCSS token-based design system switchable at runtime with no JavaScript overhead.

Features

Everything you need, nothing you don't

SanityPocketbase

CMS-agnostic by design

Swap from Sanity to Pocketbase — or any headless CMS — by changing one environment variable. Zero component changes required.

React Router v7

SSR on every request

React Router v7 in framework mode. Data loads server-side — no loading spinners, no client waterfalls, no hydration mismatches.

Tailwind v4

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.

TypeScript strict

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.

Frequently asked questions