Topics
v6.0.0
On this page · sections

SPA vs MPA vs Hybrid

Architecture choice is about who renders HTML and how navigation works — not “SPA uses React, MPA doesn’t.” Interviewers test CWV trade-offs and migration strategy.

ArchitectureNavigationFirst visitRepeat navigationSEO
CSR SPAClient router, no reloadSlow LCPFast INPNeeds prerender
MPAFull document per URLFast LCPFull reloadNative HTML
SSR hybridServer HTML + client navFast LCPFast INPHTML per URL

SPA vs MPA — Core Model

Definition

An MPA serves a full HTML document per URL — browser navigates, server returns new page, JS/CSS may reload.

An SPA loads one shell HTML file, then client-side routing swaps views without full document reload.

// SPA — client router function navigate(path) { history.pushState({}, '', path); renderView(path); // swap DOM, no document reload } // MPA — full navigation function goToCheckout() { window.location.href = '/checkout'; // new document }
MPA: GET /home → full HTML · GET /about → full HTML SPA: GET / → shell + JS · route change → JS router, no reload

History API — pushState / popstate enable SPA URLs without hash fragments. SSR SPA (Next.js, Remix) server-renders first paint, then hydrates — still one client router after load.

If JS fails to load in a pure CSR SPA, users see a blank shell. Hybrid/SSR mitigates by shipping meaningful HTML first.

Interview: Answer with navigation + who renders HTML — not framework names.

Core Web Vitals Trade-offs

Definition

ArchitectureCold LCPWarm route changeSEO crawl
CSR SPASlowFastNeeds prerender
MPAFastFull reloadNative HTML
SSR hybridFastFast (client nav)HTML per URL

First visit: MPA or SSR hybrid usually wins LCP — HTML arrives with content. Pure CSR SPA often loses LCP because the largest element renders only after JS executes.

Repeat navigation: SPA wins INP on in-app route changes — no full document reload. MPA pays full navigation cost every click.

CLS: Both fail with late fonts, ads, or skeleton → content swap.

// CSR SPA — LCP waits for JS document.getElementById('root').innerHTML = ''; // ... download bundle, parse, execute ... renderApp(); // LCP element appears here // SSR hybrid — LCP in initial HTML // Server sends: <main><h1>Dashboard</h1>...</main>

Code splitting reduces initial JS but delays route LCP if the LCP element lives in a lazy chunk. MPAs benefit from bfcache on return navigation.

Interview: Hybrid gives good first LCP plus SPA-speed subsequent navigations — measure field data per template, not architecture label alone.

When SPA Wins

Definition

Choose SPA when the product is highly interactive with frequent in-app navigation and state that must persist across views.

'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; export function OrdersPanel() { const [filters, setFilters] = useState({ status: 'open', region: 'us' }); const router = useRouter(); return ( <select value={filters.status} onChange={(e) => setFilters({ ...filters, status: e.target.value })} > <option value="open">Open</option> <option value="closed">Closed</option> </select> ); }

Concrete examples: dashboards, editors, trading terminals, design tools.

  • Authenticated apps — SEO irrelevant; interaction speed matters
  • Persistent client state — filters, undo stacks, WebSocket feeds
  • Rich interactions — drag-drop, canvas, multi-step wizards
  • Offline / PWA — service worker caches one shell

Name session shape — “50 navigations per session, no SEO” beats abstract “better UX.”

Pure CSR SPA OK for internal admin behind VPN when TTI is verified. Route-level code splitting required — shipping entire app on first load kills mobile perf.

Interview: SPA wins when amortized navigation cost exceeds initial load penalty over typical session length.

MPA & Hybrid Patterns

Definition

Hybrid means server renders HTML per URL, client hydrates and optionally client-navigates afterward.

// Next.js — SSG marketing page export default async function PricingPage() { const plans = await getPlans(); return ( <main> <h1>Pricing</h1> <PlanGrid plans={plans} /> </main> ); } export const revalidate = 3600; // ISR
<!-- Astro island — MPA page, one interactive widget --> <article>Static markdown — zero JS</article> <BuyButton client:visible data-sku="pro" />
  • SSG — pre-builds HTML at deploy; docs and marketing
  • SSR — renders per request; personalized data
  • Islands — small interactive widgets in static HTML
  • HTMX — swaps HTML fragments without SPA framework

MPA wins when pages are mostly static, CMS-driven (WordPress, Contentful), or teams want maximum simplicity — CDN HTML, no Node server.

Split www (SSG MPA) from app. (SPA/hybrid) for independent deploy and perf budgets.

Interview: Hybrid adds hydration cost — can hurt INP if main thread blocked during large client tree hydrate.

Migration Strategy

Definition

Start with requirements, not framework hype. Map routes by SEO need, interactivity, and traffic.

// nginx strangler — route-based split // location /dashboard { proxy_pass http://next-app; } // location / { proxy_pass http://legacy-php; } function resolveStack(pathname) { if (pathname.startsWith('/dashboard')) return 'next-app'; return 'legacy-mpa'; }

Strangler pattern: new routes on Next.js behind reverse proxy; legacy MPA serves unchanged pages.

Use Module Federation or iframe only when teams must deploy independently — operational cost is real.

Never big-bang rewrite unless MPA is unmaintainable and features can freeze for quarters.

Strangler milestones: route split → perf baseline (CrUX) → SEO preservation (URL parity) → sunset legacy

Micro-frontends justify cost with multiple autonomous teams, different release cadences, clear domain boundaries — not one team of eight. Plan dual-stack exit criteria or security debt accumulates.

Interview: “Rewrite everything in React” without migration path, perf baseline, or SEO plan loses staff loops.

Senior Interview Summary

MPA = full HTML per nav. SPA = one shell, JS router. Hybrid = server HTML + optional client nav.

CWV

Cold LCP favors MPA/SSR. Warm INP favors SPA. Measure CrUX per surface.

When SPA wins

Authenticated, interactive, persistent state, high in-session navigation count.

When MPA/hybrid wins

Marketing, SEO, static content, fast first paint, small teams.

Migration

Strangler over big-bang. URL parity. CWV before/after. Dual-stack sunset date.

Best mental model

First visit → who ships HTML with content? Repeat nav → full reload vs client router? SEO → crawlers need HTML per URL?

Practical rules

Public marketing homepage → MPA/SSG, not pure CSR SPA Logged-in dashboard → SPA or hybrid app zone Migration → route ownership matrix + perf baseline

What to say in interviews

Pick architecture for dashboards vs marketing sites with CWV reasoning. Describe strangler migration with measurable milestones. Explain when micro-frontends justify cost vs monorepo + strangler.

Last updated on