Frontend application architecture becomes important the moment the codebase no longer fits in one team’s head and every change starts touching routing, shared utilities, and neighboring features. That is where app shells, feature modules, and strict rules around what belongs in the shared kernel become necessary.
The practical value of the chapter is that it helps separate product flow from platform structure. Good frontend modularity speeds delivery not because the folders look cleaner, but because ownership, import boundaries, and public module APIs become predictable.
For design reviews, it is a strong entry point into modular-monolith frontend thinking: how to keep the shell thin, how to stop the shared layer from expanding, and how to evolve the application without jumping into micro-frontends too early.
Practical value of this chapter
Design in practice
Turn guidance on frontend application boundaries, modularity, and a controlled shared kernel into concrete decisions for composition, ownership, and client-runtime behavior.
Decision quality
Evaluate architecture through measurable outcomes: delivery speed, UI stability, observability, change cost, and operating risk.
Interview articulation
Structure answers as problem -> constraints -> architecture -> trade-offs -> migration path with explicit frontend reasoning.
Trade-off framing
Make trade-offs explicit around frontend application boundaries, modularity, and a controlled shared kernel: team scale, technical debt, performance budget, and long-term maintainability.
Context
Why do we need frontend architecture?
This chapter turns the high-level frontend architecture overview into the structure of a real application: shell, modules, and shared kernel.
In a complex frontend product, application architecture defines not only code structure, but also how independently teams can move, how quickly screens load, and where the public contracts between interface areas actually live.
A useful rule is to design module boundaries before debating state libraries or framework patterns. Boundaries are where it becomes clear what is truly shared and what simply has not been decomposed into domains yet.
Architectural frame
The app shell owns the frame, not business logic
The shell should carry layout, navigation, identity, telemetry, and platform hooks. Business features should not turn it into a shared monolith.
Feature modules align with bounded contexts
Catalog, checkout, billing, editor, or reporting should have their own screens, data hooks, and internal UI primitives instead of constantly reaching into a global shared layer.
The shared kernel must stay small and expensive to change
Design tokens, routing primitives, auth session, telemetry adapters, and a few platform utilities belong there. Everything else starts local to a domain.
Public contracts matter more than convenient imports
Each module needs entrypoints, versionable APIs, and clear ownership. Otherwise the app turns into a tightly coupled graph of accidental dependencies.
Related
Decomposition Strategies
A frontend app scales better when module boundaries match product bounded contexts.
Boundary rules
Imports only flow downward through the architecture
A feature module may depend on the shared kernel, but not directly on a neighboring feature. Cross-domain scenarios should go through a public contract or orchestration layer.
UI components split into local and platform primitives
Buttons, modal shells, and token-aware typography belong to the platform. Domain widgets like a pricing table or document toolbar should not leak into shared too early.
Routing is architecture, not just DX
The route tree should reflect ownership and lazy-loading boundaries. Nested layouts and loaders should not accidentally pull the whole runtime of every module.
Critical cross-cutting concerns connect the same way everywhere
Telemetry, error boundaries, auth guards, and feature-flag evaluation need one integration pattern so debugging and rollout do not depend on local team style.
Team operating model
- Each feature module has an owner team, a public API, and explicit deprecation rules.
- The shared kernel goes through stricter review than local domain code because its blast radius is much higher.
- Architectural dependency rules are captured in ADRs or import-policy checks, not in informal agreements.
- Refactoring starts with clearer module boundaries, not with an early jump to micro-frontends.
Practical quality bar
Independent change
A new feature can be added inside one domain without a cascade of edits across neighboring modules and shared utilities.
Transparent dependencies
From the import graph and route tree, it is obvious where the source of truth lives and who owns each public entrypoint.
Controlled shared kernel
The common layer stays small, versionable, and rarely changed instead of becoming a dumping ground for everything reusable.
Related chapters
- Why do we need frontend architecture? - gives the map of the full frontend track and explains why application boundaries affect delivery speed.
- Frontend Architecture for Design Systems - adds the platform perspective: design systems, governance, and the operating model for shared layers.
- Frontend data layer: REST, GraphQL, BFF, and orchestration - continues the boundary discussion at the point where feature modules meet backend aggregation.
- State and cache architecture in frontend applications - shows how architectural boundaries influence the source of truth and invalidation design.
- Modular frontend vs micro-frontends - helps clarify when a modular monolith is enough and when stronger team boundaries are justified.
- Decomposition Strategies - adds general architecture context for bounded contexts, coupling, and the evolution of module boundaries.
