frontend-architecture
Frontend Architecture
Concept of the skill
Frontend architecture is the discipline of deciding, on purpose, three things about a frontend codebase: where code lives, what is allowed to depend on what, and who owns mutable state — and then defending those decisions so they survive growth. Its central insight is that the folder tree you see is only the surface; the architecture that actually governs changeability is the import graph beneath it. The skill works at three structural layers. Module organization chooses an organizing model — feature-sliced (features/<feature>/{ui,model,api}), layered (components/, hooks/, services/, pages/), or domain-driven (domains/<domain>/{ui,logic,data}) — and accepts its trade-offs as the codebase scales. Component layering separates pure primitives, feature-composed components, and data-connected components, watching the composed↔connected boundary where most dependency tangles begin. State ownership decides location, normalization, derivation, and write-ownership for each piece of state, and keeps cache-managed server state separate from ephemeral client state. Holding all three together is import-direction enforcement: a mechanically checked rule (shared may not import features; one feature may not import another) that fails the build when a change crosses an intended boundary, so the structure degrades through deliberate decision rather than through a thousand unreviewed shortcut imports.
Coverage
Frontend architecture decides three things: where code lives (folder and module structure), what depends on what (allowed import direction), and who owns mutable state (component-local, feature-scoped, or global). This skill covers the common organizing models — feature-sliced (features//{ui,model,api}), layered (components/, hooks/, services/, pages/), and domain-driven (domains//{ui,logic,data}) — and the trade-offs each makes when the codebase grows from a few features to dozens.
Component layering separates primitives (no business knowledge, configurable purely through props — Button, Input, Stack), composed components (combine primitives with feature-specific layout, still no data fetching — OrderSummary, AddressForm), and connected components (own data fetching, mutation, and routing — OrderDetailPage). The boundary between composed and connected is the most common source of dependency tangles: a "shared" composed component that quietly reaches into a feature-specific store creates a back-edge that breaks the dependency graph.
State shape decisions span four axes: location (component, context, store), normalization (entity-keyed vs. nested), derivation (computed at read time vs. stored), and ownership (who can write). The shape choice determines what re-renders, what stays consistent across views, and what becomes a source of bugs when a mutation forgets to update one of several copies. Server state (data fetched from an API, cache-managed) and client state (UI-only, ephemeral) have different requirements and benefit from being managed by different tools.
Import direction enforces the architecture. A rule like "shared/ may not import from features/, and feature A may not import from feature B" is checkable with ESLint boundary plugins and tells the team at PR time when a change crosses an intended layer. Without enforcement, the structure degrades within months — a single shortcut import becomes the norm.
Philosophy of the skill
The folder structure is not the architecture; the import graph is. A pretty folder tree with cyclic imports between features is architecturally worse than a flat folder with strict one-way dependencies. Optimize for "where would I look for this" (colocation by feature) and "what changes together stays together" (cohesion) over imposed taxonomy.
Server state and client state are different problems. Mixing them in a single store creates cache-invalidation bugs that look like rendering bugs. Use the same tool for fetching, caching, and revalidating server data; reserve global client state for genuinely cross-cutting UI concerns (theme, current user, route).