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.
| Architecture | Navigation | First visit | Repeat navigation | SEO |
|---|---|---|---|---|
| CSR SPA | Client router, no reload | Slow LCP | Fast INP | Needs prerender |
| MPA | Full document per URL | Fast LCP | Full reload | Native HTML |
| SSR hybrid | Server HTML + client nav | Fast LCP | Fast INP | HTML 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 reloadHistory 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
| Architecture | Cold LCP | Warm route change | SEO crawl |
|---|---|---|---|
| CSR SPA | Slow | Fast | Needs prerender |
| MPA | Fast | Full reload | Native HTML |
| SSR hybrid | Fast | Fast (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 legacyMicro-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
Navigation model
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 baselineWhat 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.