Component architecture that actually scales
Learn how to structure scalable React codebases using a 3-layer component model. Eliminate code duplication, improve maintainability, and clean up components.

Every codebase I have inherited had the same disease: a components folder with 180 files, no ownership, and three slightly different buttons. The fix is not a new framework. It's agreeing on boundaries before the second developer joins.
Three layers, no exceptions
I split the UI into primitives, composites, and features. Primitives know nothing about the product. Composites know about a domain. Features know about a route.
- Primitives — buttons, inputs, cards. Zero data fetching, zero domain words.
- Composites — ProjectCard, BlogCard. They accept domain types as props.
- Features — full sections wired to loaders and server functions.
Data flows down, intent flows up
A composite should never fetch. If a card needs data, the feature above it fetches and passes it in. This single rule makes 90% of your components trivially testable and instantly reusable.
// feature layer — owns the data
export function WorkSection() {
const { data: projects } = useSuspenseQuery(projectsQuery);
return (
<Grid>
{projects.map((p) => (
<ProjectCard key={p.slug} project={p} />
))}
</Grid>
);
}
// composite layer — owns the presentation
export function ProjectCard({ project }: { project: Project }) {
return <article className="rounded-2xl">{project.title}</article>;
}If you cannot describe what a component knows in one sentence, it knows too much.
Naming is the cheapest documentation
Name files after what they render, not how they render it. pricing-table.tsx survives a redesign; three-column-grid.tsx does not.