Series MapLesson 03 / 35
Start HereOrdered learning track

Learn Frontend React Production Architecture Part 003 Modern React Architecture Landscape

22 min read4243 words
PrevNext
Lesson 0335 lesson track0106 Start Here

title: Learn Frontend React Production Architecture - Part 003 description: Modern React architecture landscape: React as a UI runtime, framework selection, rendering strategies, SPA/SSR/SSG/streaming/RSC trade-offs, and production decision-making. series: learn-frontend-react-production-architecture seriesTitle: Learn Frontend React Production Architecture order: 3 partTitle: Modern React Architecture Landscape tags:

  • react
  • frontend
  • architecture
  • rendering
  • nextjs
  • vite
  • react-router
  • production date: 2026-06-28

Part 003 — Modern React Architecture Landscape

0. Core Thesis

React production architecture is not decided by asking:

"Should we use React?"

That question is too small.

The real production question is:

"Where should each unit of UI work happen: build time, request time, server runtime, edge runtime, browser runtime, cache layer, or background data layer?"

React is the UI model. Production architecture is the placement of work.

A weak React engineer thinks in components only.

A strong React engineer thinks in:

  • rendering location
  • data ownership
  • cache boundary
  • hydration cost
  • network path
  • security boundary
  • deployment topology
  • user-perceived latency
  • failure mode
  • operational observability
  • long-term change cost

This part builds the landscape map so later parts can go deep without mixing unrelated decisions.


1. Kaufman Frame

Josh Kaufman's method starts by deconstructing the skill.

For React production architecture, the skill is not one skill. It is a cluster of decisions.

The goal of this part is to make you able to self-correct architectural decisions.

You should be able to look at a React system and say:

  • "This does not need SSR."
  • "This route should be static."
  • "This dashboard is client-heavy, but the shell can be server-rendered."
  • "This admin module should not be coupled to the public website framework."
  • "This server component boundary is leaking browser-only assumptions."
  • "This app chose Next.js, but is still architected like a single client bundle."
  • "This Vite SPA is valid because the domain is authenticated, workflow-heavy, and not SEO-sensitive."

2. React Is Not the Whole Architecture

React lets us build UI from components. That is the base.

But a production frontend also needs:

ConcernTypical OwnerReact Solves It Alone?
UI compositionReactYes
render schedulingReact runtimeMostly
routingframework/routerNo
data fetchingframework/query layer/API clientNo
server renderingframework/runtimeNo
bundlingVite/Next/Rspack/Rollup/etc.No
deploymentplatform/CDN/containerNo
observabilitytooling/platformNo
auth/sessionapp/platform/backendNo
authorizationbackend/domain policyNo
accessibilityengineering disciplinePartly
performancearchitecture + toolingPartly
securityarchitecture + platformPartly

A top-level mental model:

React lives mostly in the browser and server/framework render layer, but the system behavior is produced by the whole chain.


3. The Main Production Question

Every React route should answer:

"What is the cheapest correct place to compute this UI?"

"Cheapest" does not mean cheapest infrastructure cost only.

It means cheapest across:

  • latency
  • CPU cost
  • memory cost
  • JavaScript shipped
  • implementation complexity
  • cacheability
  • security exposure
  • operational debugging
  • correctness risk
  • team capability

A public product page and a private regulatory case management console should not have the same architecture.

A product page needs SEO, fast first paint, cacheability, structured metadata, and stable URLs.

A case management console needs correctness, workflow state, action gating, auditability, optimistic/pessimistic command handling, realtime updates, and strong failure visibility.


4. Rendering Strategy Vocabulary

The biggest source of confusion in React architecture is mixing rendering terms.

Let's define the practical vocabulary.


4.1 CSR — Client-Side Rendering / SPA

In a pure SPA, the browser receives a minimal HTML shell and JavaScript bundle. React renders the app in the browser.

Typical Flow

Strengths

  • simple deployment to static hosting
  • great for authenticated internal apps
  • clear separation between frontend and backend
  • easy to use with Vite, React Router, TanStack Query, Zustand, Redux Toolkit
  • easier runtime model than server-rendered frameworks
  • fewer server rendering mismatch issues
  • fewer framework-specific cache semantics

Weaknesses

  • slower first meaningful render on poor devices/networks
  • SEO must be handled separately or may be weak
  • initial JS cost can become high
  • auth bootstrap can block app render
  • direct URL access must be routed to index.html
  • page metadata is harder to tailor per route without server support

Best Fit

Use CSR SPA when:

  • app is authenticated
  • SEO is not important
  • users return often
  • app is interaction-heavy
  • routes require complex client state
  • backend APIs already exist
  • static hosting/CDN simplicity matters
  • team wants low framework complexity

Bad Fit

Avoid pure CSR when:

  • public content must rank in search
  • first render matters for anonymous users
  • content is cacheable and should be generated close to the server
  • device/network conditions are poor
  • marketing pages and transactional app are mixed without clear boundary

Production Examples

Good CSR candidates:

  • admin consoles
  • internal workflow tools
  • regulatory case management
  • trading dashboards behind login
  • monitoring consoles
  • developer portals behind auth
  • complex configuration UIs

Bad CSR candidates:

  • public landing pages
  • product catalogs
  • news sites
  • documentation sites needing crawlable content
  • content-heavy public portals

4.2 SSR — Server-Side Rendering

SSR means the server renders HTML for a request. The browser receives HTML that can be displayed before all client-side JavaScript finishes loading.

Typical Flow

Strengths

  • better initial HTML for users and crawlers
  • can improve perceived first load
  • route-specific metadata is natural
  • useful for dynamic pages
  • can reduce blank-screen risk

Weaknesses

  • server runtime becomes part of frontend architecture
  • hydration can be expensive
  • data fetching may increase TTFB
  • cache strategy becomes more complex
  • browser-only code can break server render
  • debugging spans browser and server
  • server capacity matters

Best Fit

Use SSR when:

  • content is dynamic per request
  • SEO matters
  • first render matters
  • metadata changes per route
  • personalization exists but is not too expensive
  • app has clear server runtime ownership

Bad Fit

Avoid SSR when:

  • all routes are behind login and heavily interactive
  • content cannot be meaningfully rendered before client data loads
  • server infrastructure maturity is low
  • team cannot operate server rendering failures
  • route mostly renders skeletons anyway

4.3 Streaming SSR

Streaming SSR sends HTML progressively instead of waiting for the entire page.

Mental Model

You divide the page into boundaries. Fast parts are sent early. Slow parts stream later.

Strengths

  • better progressive rendering
  • reduces all-or-nothing waiting
  • works well with Suspense boundary design
  • useful for mixed-latency pages

Weaknesses

  • boundary design becomes architecture
  • loading states must be intentional
  • partial failure handling matters
  • monitoring must distinguish shell vs section latency
  • careless streaming can create visual instability

Good Fit

Use streaming when:

  • page has independent sections
  • data sources have different latency profiles
  • user benefits from early partial content
  • framework supports streaming well
  • design system supports skeleton/fallback states

4.4 SSG — Static Site Generation

Static generation renders pages at build time.

Strengths

  • very fast at runtime
  • CDN-friendly
  • low server cost
  • reliable for mostly-static content
  • strong for docs, marketing, blogs, public information

Weaknesses

  • rebuild needed for changes unless paired with revalidation
  • not ideal for highly personalized content
  • build time can grow with page count
  • runtime freshness needs explicit design

Good Fit

Use SSG when:

  • content changes slowly
  • route count is manageable
  • SEO matters
  • pages are public
  • CDN caching is valuable

4.5 ISR / Revalidation / Incremental Freshness

Different frameworks use different terms, but the production idea is:

Generate or cache HTML/data, then refresh it according to a freshness policy.

Decision Questions

  • How stale may this route be?
  • Who can tolerate stale data?
  • What event invalidates the page?
  • Is revalidation time-based or event-based?
  • What happens when regeneration fails?
  • Can users see old data during regeneration?
  • Is stale content legally or operationally risky?

For regulatory/workflow systems, stale data can be dangerous. For marketing content, stale data may be acceptable for minutes or hours.


4.6 RSC — React Server Components

React Server Components are components that render ahead of time in a server environment separate from the client app or SSR server.

They change the architectural boundary.

Instead of asking:

"Can the server produce HTML?"

You ask:

"Which components never need to become client JavaScript?"

RSC Mental Model

Good Server Component Candidates

  • data-reading components
  • static layout fragments
  • content sections
  • components using server-only libraries
  • components that do not need browser state/effects/events
  • components that would otherwise ship heavy dependencies to the browser

Good Client Component Candidates

  • forms with live interaction
  • buttons with event handlers
  • drag and drop
  • charts requiring browser APIs
  • local stateful widgets
  • effects/subscriptions
  • focus management
  • browser storage
  • client-only telemetry wrappers

Common RSC Mistake

The common mistake is adding "use client" at the top of large route files because one child needs interactivity.

That turns the whole subtree into client-rendered code.

Better architecture:

// Server component
export default async function CasePage({ params }: Props) {
  const caseData = await getCase(params.caseId);

  return (
    <CasePageShell caseData={caseData}>
      <CaseActionPanel caseId={caseData.id} allowedActions={caseData.allowedActions} />
    </CasePageShell>
  );
}

// Client component
"use client";

export function CaseActionPanel({ caseId, allowedActions }: Props) {
  const [selectedAction, setSelectedAction] = useState<Action | null>(null);

  return (
    <ActionPicker
      caseId={caseId}
      actions={allowedActions}
      selectedAction={selectedAction}
      onSelect={setSelectedAction}
    />
  );
}

The server component owns data access and composition. The client component owns interaction.


5. Framework Landscape

There are many tools around React. The point is not to memorize brands. The point is to map responsibility.


5.1 Vite + React + Router

Vite is a modern build tool and dev server. A Vite React app is commonly used for SPA architecture.

Production Shape

Good Fit

  • authenticated business apps
  • dashboards
  • internal tools
  • micro-frontends
  • embeddable widgets
  • apps with existing backend APIs
  • teams wanting explicit control over data/routing/state choices

Watch Out

  • SEO is not automatic
  • route metadata needs special handling
  • bundle discipline is your responsibility
  • browser-only runtime can create slower first load
  • app shell design matters

5.2 Next.js App Router

Next.js App Router uses filesystem routing and modern React features such as Server Components, Suspense, and Server Functions.

Production Shape

Good Fit

  • public + authenticated hybrid apps
  • SEO-sensitive apps
  • content + application mixed products
  • teams needing server rendering and app framework conventions
  • pages that benefit from static/dynamic/streaming segmentation
  • route-level layouts and nested loading/error boundaries

Watch Out

  • caching semantics require discipline
  • "use client" boundary mistakes are expensive
  • server/client mental model is harder than SPA
  • framework upgrades can affect architecture
  • coupling to deployment platform may appear subtly
  • server actions require security review

5.3 React Router Modes

Modern React Router can be used in multiple modes:

  • Declarative mode
  • Data mode
  • Framework mode

The important architecture distinction:

ModePrimary Use
Declarativeclassic client routing
Dataroutes plus loaders/actions/pending states
Frameworkmore integrated routing, data, rendering conventions

Good Fit

Use React Router when:

  • you want routing without adopting a full Next-style framework
  • you need SPA or data-router architecture
  • you want explicit route objects
  • your app is authenticated/internal
  • you want gradual complexity adoption

Watch Out

  • loaders/actions introduce data ownership decisions
  • route modules become architecture boundaries
  • route-level error handling must be designed
  • mixing ad hoc fetches with loaders can create duplicate data paths

5.4 Other React Frameworks and Meta-Frameworks

You may encounter:

  • Remix heritage through React Router framework mode
  • Astro with React islands
  • Gatsby for static/content-heavy sites
  • TanStack Router/Start
  • Rspack/Rsbuild-based setups
  • custom SSR stacks

This series will stay focused on React production architecture rather than tool fandom.

The architectural question remains stable:

What is rendered where, loaded when, cached how, invalidated by whom, and observed with what signal?


6. Decision Axes

A mature React architecture decision does not start from popularity. It starts from constraints.


6.1 Audience

AudienceTypical Bias
anonymous public usersSSR/SSG/streaming/static
authenticated employeesSPA/data router
search crawlersSSR/SSG
mobile web on weak devicesless JS, server/static rendering
power usersclient-heavy interactivity
regulated usersauditability and correctness over trendiness

6.2 Content Freshness

Freshness NeedSuitable Strategy
changes yearly/monthlySSG
changes daily/hourlySSG + revalidation
changes per requestSSR
changes per userSSR or CSR after auth
changes per interactionCSR/server state
changes through workflow commandsclient UI + backend authority

6.3 Interactivity

Interactivity LevelSuitable Strategy
static contentSSG
content plus simple formsSSR/SSG + client islands
dashboard filters/chartsCSR or hybrid SSR
complex workflowCSR/data router/hybrid
realtime collaborationCSR-heavy with event ingestion
editor-like UIclient-heavy architecture

6.4 SEO and Metadata

SEO NeedSuitable Strategy
noneSPA
basic indexabilitySSR/SSG
high SEO competitionSSG/SSR with metadata discipline
user-specific private routesSEO irrelevant
documentationSSG
public case/status lookupSSR/SSG depending freshness

6.5 Cacheability

Ask:

  • Can this route be cached?
  • Is the same response valid for many users?
  • Does auth affect the HTML?
  • Is data public, private, or permission-scoped?
  • Can the CDN cache it safely?
  • What invalidates it?
  • Is stale data acceptable?

Cacheability often determines architecture more than React preference.


6.6 Failure Mode

A rendering strategy also defines how the app fails.

StrategyFailure Shape
SPAblank screen, failed JS, API fetch failure
SSRserver error page, slow TTFB, hydration mismatch
SSGstale page, broken build, missing generated route
Streamingpartial page, stuck boundary, inconsistent fallback
RSCserver/client boundary errors, serialization errors
Data routerloader/action failures, pending-state bugs

Design for failure before choosing architecture.


7. Decision Matrix

Use this as a starting point, not a dogma.

ScenarioRecommended DefaultWhy
Internal admin consoleVite SPA + React Router/Data RouterFast iteration, auth-only, interaction-heavy
Public marketing siteSSG/SSR frameworkSEO, metadata, CDN, fast first paint
E-commerce product pageSSR/SSG + revalidationSEO + freshness + cacheability
Checkout flowSSR shell + client transactional UIreliability + interaction
Regulatory case managementSPA or hybrid app, strong API boundaryworkflow correctness dominates SEO
Public case status lookupSSR or SSG+revalidationpublic URL + freshness constraints
Analytics dashboardSPA/hybrid with server-state cacheclient filters/charts, API-driven
Documentation portalSSGstable content, CDN-friendly
Realtime collaboration toolclient-heavy + event architecturebrowser state and events dominate
Mixed public/private SaaSNext.js App Router or split appspublic SEO + authenticated app complexity

8. Split App vs One App

One of the most important architecture decisions is whether to build one frontend or multiple frontends.

Bad Default

One repo, one framework, one deployment, one routing tree, every route inside it forever.

This can work, but often becomes accidental monolith.

Better Question

"Do these surfaces share lifecycle, audience, security boundary, performance budget, and deployment cadence?"

Split Candidate Matrix

SurfaceSplit?Reason
marketing site vs admin consoleoften yesdifferent SEO/performance/auth needs
public docs vs SaaS appoften yesdocs can be static
customer portal vs internal opsmaybedifferent roles and compliance
checkout vs catalogmaybefailure isolation
design system packageyesshared governed dependency
workflow module inside same appnot alwaysdomain cohesion may matter more

Split Architecture

Do not split because of organizational politics. Split because boundaries differ.


9. Architecture Smells

Smell 1 — Framework Chosen Before Constraints

"We use Next.js because everyone does."

Better:

"We use Next.js because this product combines public SEO-sensitive pages, authenticated dashboards, route-level layouts, and server-rendered content with clear caching policies."

Smell 2 — SPA Used for Public Content Without Intent

If the page must be indexed, shared, previewed, and loaded quickly by anonymous users, a pure SPA may be the wrong default.

Smell 3 — SSR Used but Still Fetches Everything After Hydration

If server-rendered HTML is mostly skeleton and all data is fetched after hydration, you may be paying SSR complexity without getting the benefit.

Smell 4 — RSC Converted to Client Components Accidentally

A single interactive child should not force the entire route subtree into client JavaScript.

Smell 5 — One Frontend for Incompatible Surfaces

A marketing site, docs, customer portal, and admin console have different constraints. One repo may be fine. One app runtime may not be.

Smell 6 — No Cache Invalidation Story

Caching without invalidation policy is not architecture. It is a future incident.

Smell 7 — No Failure Model

If the team cannot answer "what does the user see when this loader/API/stream/chunk fails?", the architecture is incomplete.


10. Production Decision Flow


11. Architecture Records

Every non-trivial frontend architecture should produce an ADR.

ADR Template

# ADR: Rendering Strategy for <Surface>

## Status

Accepted / Proposed / Superseded

## Context

- audience:
- public/authenticated:
- SEO need:
- freshness:
- interactivity:
- data sensitivity:
- expected traffic:
- device/network assumptions:
- team constraints:

## Decision

We will use:

- rendering:
- router:
- data fetching:
- caching:
- deployment:
- observability:
- fallback strategy:

## Consequences

Positive:

- ...

Negative:

- ...

Risks:

- ...

Mitigations:

- ...

## Revisit Trigger

Revisit this decision if:

- traffic changes
- SEO requirements change
- latency budget is violated
- auth model changes
- framework support changes
- team operational maturity changes

An ADR prevents "architecture by memory".


12. Case Study — Regulatory Case Management Frontend

Assume you are building a regulatory enforcement lifecycle UI.

Characteristics:

  • authenticated
  • role-based
  • workflow-heavy
  • long-lived cases
  • audit-sensitive
  • action availability depends on case state
  • complex filters/search
  • large tables
  • attachments
  • comments
  • escalation
  • realtime-ish updates
  • data freshness matters
  • SEO irrelevant

Bad Default

Use SSR everywhere because it is trendy.

Better Default

Use either:

  1. Vite SPA + React Router/Data Router + TanStack Query/RTK Query + strong API contracts, or
  2. Hybrid framework with server-rendered shell and client-heavy workflow modules.

Why

The system's hardest problem is not first public paint. It is correct workflow behavior.

Key architectural concerns:

  • API contract
  • permission-aware UI
  • command idempotency
  • optimistic vs pessimistic updates
  • action-state consistency
  • stale data handling
  • observability for failed actions
  • table virtualization
  • form validation
  • audit trace presentation
  • resilient navigation

Possible Architecture

The key boundary is not "page vs component". It is "query vs command", "view vs action", "client affordance vs backend authority".


13. Case Study — Public Enforcement Decision Portal

Assume the same organization has a public page where citizens can search published enforcement decisions.

Characteristics:

  • public
  • SEO important
  • shareable URLs
  • maybe cacheable
  • data freshness matters but perhaps not by the second
  • filtering/search
  • public metadata
  • legal correctness matters

Better Default

SSR or static generation with revalidation.

Why

  • public pages need stable URLs
  • crawlers need meaningful content
  • metadata should be route-specific
  • many users can share cached content
  • not all interactivity requires full SPA

Possible Architecture

Same organization. Same React ecosystem. Different architecture.

That is the point.


14. Anti-Pattern Catalog

14.1 The Hype-Driven Framework

Symptom:

  • framework selected before constraints
  • team cannot explain rendering mode
  • no cache policy
  • no failure model
  • no performance budget

Consequence:

  • over-complex architecture
  • slow delivery
  • hidden operational cost

Corrective action:

  • write an ADR
  • classify routes by rendering need
  • split incompatible surfaces
  • remove unused framework features

14.2 The "Everything Is SPA" Default

Symptom:

  • public pages are blank without JS
  • metadata is generic
  • social previews are wrong
  • LCP is poor
  • crawlers get thin content

Corrective action:

  • move public content to SSG/SSR
  • split marketing/docs from app
  • make app shell explicit
  • preserve SPA only where it fits

14.3 The "Everything Is SSR" Default

Symptom:

  • authenticated app pays server cost for little benefit
  • server render outputs skeletons
  • all useful data loads after hydration
  • server runtime becomes bottleneck

Corrective action:

  • measure actual first content value
  • move interaction-heavy modules to client
  • use static/client architecture when SEO is irrelevant
  • keep SSR for routes that benefit

14.4 The Accidental Client Boundary

Symptom:

  • "use client" appears at the top of page/layout modules
  • server data fetching moves into effects
  • bundle grows
  • RSC benefits disappear

Corrective action:

  • isolate interactivity to leaf components
  • pass serializable props
  • keep server-only work server-side
  • audit client bundle composition

14.5 The Cache Without Owner

Symptom:

  • stale data incidents
  • multiple caches disagree
  • no invalidation trigger
  • "refresh page" becomes support advice

Corrective action:

  • document cache owner
  • define freshness policy
  • define invalidation events
  • instrument cache hit/miss/staleness
  • avoid caching sensitive personalized data unsafely

15. What Top Engineers Do Differently

A top frontend engineer does not ask:

"Which framework is best?"

They ask:

  • What is the user journey?
  • What must be visible before JS?
  • Which data is public/private?
  • Which data can be stale?
  • Which route is cacheable?
  • Which route is mostly interaction?
  • Which page is SEO-sensitive?
  • What fails independently?
  • What can be statically generated?
  • What must run close to data?
  • What must run in the browser?
  • What must be observed?
  • What must be reversible?

That is architecture.


16. Deliberate Practice

Take any existing React app and classify 10 routes.

For each route, fill this table:

RoutePublic/AuthSEOFreshnessInteractivityData SensitivityRecommended Rendering
/PublicHighWeeklyLowPublicSSG
/cases/:idAuthNoneSeconds/minutesHighPrivateSPA/Hybrid
/decisions/:idPublicHighDaily/eventMediumPublicSSR/SSG+revalidation

Then write one ADR for the most ambiguous route.


17. Self-Correction Checklist

Before choosing an architecture, answer:

  • Is the route public or authenticated?
  • Does SEO matter?
  • Does social preview matter?
  • Can the content be cached?
  • How fresh must the data be?
  • Is stale data safe?
  • How interactive is the route?
  • What is the user device/network assumption?
  • What happens before JavaScript loads?
  • What happens if hydration fails?
  • What happens if the API fails?
  • What happens if a streamed section fails?
  • What is the rollback strategy?
  • Who owns cache invalidation?
  • Who operates the server runtime?
  • How will performance be measured?
  • How will errors be observed?
  • Is the chosen framework solving a real problem?

18. Production Heuristics

Use these as defaults, not laws.

  1. Public content should usually not be pure CSR.
  2. Authenticated workflow-heavy apps do not automatically need SSR.
  3. Static generation is underrated for stable public content.
  4. Server rendering is useful only if server-rendered content is meaningful.
  5. Streaming helps only when boundaries map to real latency differences.
  6. RSC helps when server/client boundaries are intentionally designed.
  7. Framework features are liabilities unless you understand their failure modes.
  8. Cache invalidation is part of the feature, not post-deployment cleanup.
  9. Splitting apps is acceptable when surfaces have different constraints.
  10. Architecture should be documented as decisions, not tribal knowledge.

19. Summary

React production architecture is about placing work correctly.

The main rendering choices are:

  • CSR SPA
  • SSR
  • streaming SSR
  • static generation
  • revalidation
  • React Server Components
  • hybrid combinations

No strategy is universally superior.

The best architecture is the one whose constraints match:

  • audience
  • interactivity
  • SEO
  • freshness
  • cacheability
  • security
  • failure model
  • operational maturity
  • team capability

In the next part, we move from app-level architecture to component-level architecture.

You will learn how to design component boundaries so a React codebase stays composable, testable, and evolvable instead of degenerating into page-sized scripts with JSX.


20. Source Anchors

Use these official docs as anchors for keeping this part current:

  • React docs — React components and UI model: https://react.dev/
  • React docs — Server Components: https://react.dev/reference/rsc/server-components
  • Next.js docs — App Router: https://nextjs.org/docs/app
  • Next.js docs — Server and Client Components: https://nextjs.org/docs/app/getting-started/server-and-client-components
  • React Router docs — Picking a Mode: https://reactrouter.com/start/modes
  • Vite docs — Guide and production build: https://vite.dev/guide/, https://vite.dev/guide/build
Lesson Recap

You just completed lesson 03 in start here. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.