SPA vs MPA: When to Use Which
The fundamental architectural decision in web development is whether to build a Single-Page Application (SPA) or a Multi-Page Application (MPA).
Single-Page Application (SPA)
In an SPA, the browser loads a single HTML page and then dynamically updates the content using JavaScript. Navigation between "pages" is handled client-side — no full page reloads.
Examples
- React apps with client-side routing (
react-router) - Angular apps (
@angular/router) - Vue apps (
vue-router)
Pros
- Fast navigation: Only data changes, not the whole page
- Rich interactivity: Complex client-side logic, animations
- Shared state: JavaScript state persists across "pages"
- Offline support: Can cache data and work without a server
Cons
- Large initial bundle: All JavaScript must download before the app works
- SEO challenges: Search engines struggle with client-rendered content
- Memory leaks: State accumulates in the browser tab
- Slow Time to First Byte (TTFB): Server just sends a shell, not real content
Multi-Page Application (MPA)
In an MPA, every URL maps to a server-rendered HTML page. Navigating between pages causes a full page load.
Examples
- Traditional server-rendered apps (Rails, Django, Laravel)
- Modern SSR/SSG: Next.js with SSR/SSG, Nuxt.js with SSR/SSG
Pros
- Instant rendering: Server sends complete HTML on first load
- Better SEO: Search engines see real content
- Lower memory usage: Browser doesn't hold state between pages
- Smaller bundles: Only the JS for the current page loads
Cons
- Full page reloads: Slower navigation, lost state
- More server work: Each page requires server rendering
- Limited interactivity: Complex client-side logic is harder
Modern Hybrid Approaches
Server-Side Rendering (SSR)
The server generates the full HTML on each request, then the client takes over for interactivity.
Next.js: getServerSideProps — renders on every request
Nuxt.js: asyncData — renders on every request
Tradeoff: Fast initial load + SEO, but server must render every page.
Static Site Generation (SSG)
The server generates HTML at build time, not at request time.
Next.js: getStaticProps — generates at build time
Nuxt.js: generate — pre-renders all pages
Tradeoff: Blazing fast initial load + can be CDN'd, but content must be known at build time.
Incremental Static Regeneration (ISR)
Static pages that can be updated in the background after build.
Next.js: revalidate option in getStaticProps
Tradeoff: Static performance + dynamic updates, but with eventual consistency.
Decision Matrix
| Use case | Choose |
|---|---|
| Content site (blog, marketing) | MPA / SSG — SEO + speed |
| Dashboard, admin panel | SPA — rich interactivity |
| E-commerce | Hybrid (SSR/SSG) — SEO + performance |
| Chat, collaboration | SPA + WebSockets — real-time |
| High traffic, read-heavy | MPA / SSG — CDN cacheable |
The Rendering Triangle
You can pick any two:
- ✅ Fast initial load
- ✅ Search engine friendly
- ✅ Rich interactivity
SPA gives you #1 and #3 (not #2). MPA gives you #1 and #2 (not #3). SSR/SSG gives you #2 and #3 (slower than SSG).