Bulletproof React
Not a boilerplate but a showcase of architecture patterns — organise a React app by feature, keep data access out of components, and wire in testing, mocking and error tracking from day one.
On this page
Bulletproof React is one of the best free resources on structuring large React applications. The important thing to know is what it isn’t: it’s not a starter kit to clone. It’s a collection of patterns, each of which you can adopt on its own.
Where I’d already got to — and where it hurt
Before reading it I’d converged on sensible data layers: API calls → services → transforms into domain models → React Query. That part was clean. The mess was elsewhere: big, complex components and “useSomethingLogic” hooks that became dumping grounds for anything that didn’t fit. Bulletproof React’s answer is mostly about boundaries.
The patterns worth adopting
- Feature folders. Group code by feature (
features/workflows,features/auth), each with its own components, API hooks, types and tests — instead of globalcomponents/,hooks/,utils/folders that grow forever. When one page hosts several features, treat tabs as nested routes. - Layouts per page. A navigation layout plus a content layout, chosen per route, so shared chrome stays mounted and doesn’t re-render between pages.
- Soft auth in the layout. Check authentication in the layout and redirect, rather than conditionally rendering whole trees, and cache the current user with your data library.
- Feature-level permissions, not a global RBAC wrapper. A wrapper works for routes but can’t express “you can view this but not edit it”, and it tends to re-render the whole page. Put permission checks next to the thing they protect — and remember the server is the real authority.
- Start fetching before you render. Route loaders kick off the React Query request before the component mounts, so the data is often cached by the first render.
- Small stores per feature rather than one global store. Most “global state” is really server cache.
- Mock the network in development. MSW in the browser, with factory-built fake data, lets you build whole features before the backend exists — see MSW (Mock Service Worker).
- Name tests by intent:
.test.tsfor unit,.spec.tsfor integration, stories for visual and interaction tests. More in React Testing Strategy.
Trade-offs
Feature folders need discipline about what counts as “shared”, or everything drifts back into a common folder. And not every app needs a meta-framework: for an internal tool behind a login, a static single-page app can be cheaper to host and simpler to run than server rendering.
In practice
I used these patterns to plan the re-architecture of a large internal React app. One choice I’d repeat: I tried the patterns on a personal project first rather than refactoring the work codebase while I was still learning them. Once they’d proven themselves, the proposal for the team was concrete, with a working example instead of a slide. Related habits: SOLID React and API Modelling.
- #react
- #architecture
- #project-structure
- #react-query
- #zustand
↩ Linked from (4)
- API ModellingEvergreen
…Rolling Out an API Gateway. Feature-based structure keeps these adapters next to the features that use them (Bulletproof React).
Internal Developer Platform · Where Platforms Fit: DDD Subdomains · API Modelling · Bulletproof React · Zustand Transient Updates · AJAX Polling
- SOLID ReactGrowing
…that touched ten files — not pre-emptively. These habits sit naturally inside the feature-based structure of Bulletproof React.
- Zustand Transient UpdatesEvergreen
…eats prop and setState cascades. The transport side of this lives in WebSockets, and the architecture side in Bulletproof React.
↪ Links to (4)
Related by topic
- Growingcase study
A Testing Strategy Teams Actually Adopted
Frontend craft - Growingcase study
Building a Graph Component Library
Frontend craft - Growingcase study
Chairing a Cross-Team UI Guild
Career - Seed
Convex
Frontend craft