Production ready

React Router v7
Starter Kit

A minimal but complete foundation for SSR React apps — with type-safe loaders & actions, Zod validation, shadcn/ui, TailwindCSS v4, and commit-safe tooling wired up from day one.

terminal
# scaffold
pnpm create react-router7 new my-app
cd my-app

# install & run
pnpm install
pnpm dev
React Router v7 SSR, loaders, actions, file-based routing
TailwindCSS v4 CSS-first config, zero JS overhead
shadcn/ui Unstyled, accessible component primitives
TypeScript strict Full strictness, path aliases via tsconfig
Zod v4 Schema validation on server, errors sent to client
Vite HMR dev server, optimized production build
ESLint + Prettier Flat config, format on save
Husky + commitlint Pre-commit lint gate, conventional commits
01

Intent-based action routing

A single action() per route handles all mutations via a discriminated intent field — create, update, delete.

02

Optimistic UI via useFetcher

Mutations reflect immediately before the server responds. Revalidation syncs state on completion. No external state manager needed.

03

Server-only guard

Add import "@/lib/server/server-only" to any file that must never reach the client bundle. Throws loudly if imported on the browser.

04

Two-level error boundaries

Root boundary replaces the full document. Route boundary keeps the nav shell visible and handles 404s, 403s, and unexpected errors per route.

05

Feature-based folder structure

Each feature owns its components, server code, types, and schemas. Routes import from features — features never import from routes.

06

Swappable data layer

The mock in-memory store matches the same async interface a real ORM would. Swap Prisma or Drizzle in by replacing function bodies only.

app/
├── components/
│ ├── layout/app-layout.tsx # nav, loading bar, footer shell
│ ├── root-error-boundary.tsx # full-page error (root level)
│ └── route-error-boundary.tsx # in-page error (route level)
├── features/todos/ # feature slice
│ ├── components/
│ ├── server/
│ │ ├── todo.schema.ts # zod schemas
│ │ └── todo.server.ts # data layer (server-only)
│ └── types/
├── lib/server/
│ ├── http.ts # ok / fail / notFound helpers
│ └── server-only.ts # client-import guard
├── routes/
│ ├── home.tsx
│ ├── todos.tsx # loader + action demo
│ └── not-found.tsx # catch-all 404
└── types/index.ts # shared ActionResponse<T>