Note

How frontend architecture evolves as a team scales

A real-world case study on how frontend architecture evolves as a team grows — the honest version, including the tradeoffs nobody talks about.

2026-08-31·6 min read
Frontend ArchitectureTeam ScalingCase Study

Most articles about frontend architecture show you the destination: the clean folder structure, the mature design system, the fully-tested codebase. What they rarely show is the path — the messy, honest one, full of decisions that made sense at the time and stopped making sense later.

I put together a small open-source case study to walk through that path directly: how the architecture behind a real internal product evolved as the team behind it grew from two developers to a mid-size frontend team.

Same product, three very different stages

To make the evolution concrete, the case study follows one fictional product, FlowDesk, through three stages — or "eras" — each with its own team size, its own priorities, and its own architecture.

FlowDesk starts as a simple team directory. As the team behind it grows, so does the product: task management gets added, then notifications and scheduling. Each new feature is also what forces the architecture underneath it to change.

EraTeam sizeWhat FlowDesk gainedWhat architecture had to answer
Era 12 developersA simple team directoryMinimal tooling, type-based structure, no ceremony
Era 23 developersTask managementComponent/prop sprawl, testing basics, Storybook, a late data-layer migration
Era 3Mid-to-large teamNotifications & schedulingType-based and feature-based structure coexisting on purpose

Era 1: two people, zero ceremony

With two developers, communication overhead is close to zero. Conventions can live in people's heads instead of in tooling. This era is intentionally minimal: a type-based folder structure, no testing, no component documentation, direct fetch calls instead of a data-fetching library.

None of that is a gap — it's a deliberate choice. The cost of more structure wasn't justified yet.

Era 2: growing pains

At three people, things start to strain. Screen count and component count grow fast, often because product asks for "the same component, but with a few more props" instead of a new one. Under delivery pressure, components get built as decoupled as possible — without always knowing what future requirements will look like.

This era also introduces testing, but with clear, intentional boundaries: components and hooks get covered, page-level tests are deliberately left out. And a real win shows up too — every component ships with its own Storybook story, which ends up enabling components to be shared across teams. The catch: design tokens are still hardcoded in the app, so sharing a component often means manually adjusting them to fit.

Late in this era, a data-fetching library gets introduced — which means rewriting hooks that were already working. Migrating code that already works is always more expensive than it looks from the outside.

Era 3: coexistence, not a rewrite

By the time the team reaches a mid-size frontend org, a full rewrite isn't something the business can absorb — delivery doesn't stop for it. So instead of migrating everything at once, two structural patterns are allowed to coexist on purpose: the original type-based structure stays where it is, while new work adopts a feature-based structure from day one. Old code only moves into the new pattern when it's already being touched for an unrelated reason.

One friction point never fully resolves, even by this stage: testing coverage never quite catches up with how fast the team and codebase grow. It's one of the clearest examples in the whole case study of a tradeoff that doesn't resolve itself with more people or more structure — it just becomes a long-running cost.

Why I built this

Most resources on frontend architecture teach patterns in the abstract, disconnected from the team and business context that actually justified them. I wanted to show the opposite: architecture as a series of tradeoffs made under real constraints, including the ones that don't age perfectly.

The full case study, with illustrative code for each era, is open source and available on GitHub.