A single page application (SPA) is a web app that loads one HTML shell and then updates the visible content dynamically using JavaScript, instead of requesting a full new page from the server on every navigation. Gmail, Figma, and most modern SaaS dashboards are SPAs. Understanding when this architecture helps — and when it creates unnecessary complexity — is one of the first decisions frontend teams get right or regret later.
How a SPA actually works
When you first visit a SPA, the browser downloads a JavaScript bundle (often built with React, Vue, or Svelte). That bundle:
- Renders the initial UI into a root DOM element (commonly
<div id="root">). - Listens for user actions — clicks, form submissions, route changes.
- Fetches data from APIs in the background.
- Re-renders only the parts of the interface that changed.
Navigation between "pages" is handled client-side by a router. The URL still changes (thanks to the History API), but the browser does not perform a traditional full document reload.
// Simplified client-side routing concept
const routes = {
"/dashboard": DashboardPage,
"/settings": SettingsPage,
};
function onRouteChange(path) {
const Page = routes[path] ?? NotFound;
render(<Page />, document.getElementById("root"));
}
In contrast, a multi-page application (MPA) returns a new HTML document from the server for each route. Classic WordPress sites, many e-commerce storefronts, and documentation sites often use this model.
SPA vs MPA at a glance
| Factor | SPA | MPA |
|---|---|---|
| Initial load | Heavier JS bundle | Lighter first paint |
| Subsequent navigation | Fast, no full reload | Full page request |
| SEO | Needs extra work (SSR/SSG) | Natural with server HTML |
| Interactivity | Excellent for dashboards | Depends on JS sprinkles |
| Complexity | Higher frontend state | Simpler per-page logic |
Neither is universally better. The right choice depends on user expectations and content type.
When a SPA makes sense
Highly interactive products. Tools where users spend minutes or hours clicking, filtering, dragging, and editing — analytics dashboards, design tools, project management apps — benefit from keeping state in the browser and avoiding round-trips.
Apps that feel like desktop software. If the product needs modals, side panels, optimistic updates, and real-time collaboration, a SPA (often with a component framework) is the natural fit.
Teams with strong frontend capacity. SPAs shift complexity to the client. You need engineers comfortable with state management, routing, API integration, and performance profiling.
When to avoid a SPA
Content-heavy marketing sites. Landing pages, blogs, and documentation benefit from server-rendered HTML that search engines and social previews can read immediately. Shipping a blank shell that hydrates later hurts Core Web Vitals and SEO unless you add SSR or static generation.
Simple forms with few interactions. A contact page or checkout with three steps does not need React. Server-rendered forms with progressive enhancement are faster to build and easier to maintain.
Teams without frontend specialists. A SPA that grows without discipline becomes a bundle-size problem and a testing nightmare.
The hybrid middle ground
Modern frameworks blur the line:
- Next.js and Nuxt support static generation, server-side rendering, and client-side navigation in one codebase.
- Partial hydration and islands architecture (Astro, Fresh) ship mostly static HTML and hydrate only interactive widgets.
If you need SEO and rich interactivity, a hybrid approach usually beats a pure client-rendered SPA.
Performance considerations
SPAs earn criticism for slow first loads. Mitigations that actually work:
- Code splitting so users download only the route they visit.
- Lazy loading for heavy components and charts.
- Caching API responses with tools like TanStack Query or SWR.
- Measuring with Lighthouse and real-user monitoring — not guessing.
A fast MPA will beat a bloated SPA every time. Architecture alone does not determine speed; bundle discipline does.
State management reality
As SPAs grow, "where does this data live?" becomes the hard question. Options range from React Context for small apps to Redux, Zustand, or Jotai for shared global state. The best choice is the simplest one that prevents prop-drilling without introducing ceremony.
Start local. Promote state upward only when multiple distant components need the same source of truth.
Security notes
SPAs still rely on backend APIs. Common pitfalls:
- Storing sensitive tokens in
localStorage(vulnerable to XSS) — prefer HTTP-only cookies for session tokens when possible. - Trusting client-side validation alone — always validate on the server.
- Exposing internal API keys in frontend bundles — use a backend proxy.
Migration path from MPA to SPA
Teams often migrate incrementally:
- Add a SPA for one authenticated section (e.g., dashboard) while keeping marketing pages server-rendered.
- Share design tokens and component libraries across both.
- Measure whether the migration improved user metrics before converting more routes.
Big-bang rewrites rarely pay off on schedule.
FAQ
Is React always a SPA? No. React is a UI library. You can render React on the server (Next.js), as static HTML, or as a client-only SPA.
Do SPAs work on mobile? Yes, but performance on low-end devices depends on bundle size. React Native and Flutter are separate approaches for native mobile apps.
How do search engines index SPAs? Google can render JavaScript, but server-rendered or pre-rendered HTML is more reliable. Use SSR, SSG, or dynamic rendering for public content.
Choosing with confidence
Build a SPA when your product is interaction-heavy, users stay in-session for extended periods, and you can invest in frontend engineering and performance work. Stick with multi-page or hybrid rendering when SEO, fast first paint, and content simplicity matter more than dashboard-style interactivity. The goal is not to pick the trendiest stack — it is to match architecture to how people actually use what you are building.
Framework landscape in 2026
The SPA label applies to architecture, not a single framework. Here is how teams typically choose:
- React — largest ecosystem, most hiring demand, pairs with Next.js for hybrid rendering.
- Vue — gentler learning curve, strong documentation, Nuxt for SSR.
- Svelte / SvelteKit — compiles away the framework at build time, smaller bundles by default.
- Angular — opinionated, popular in enterprise teams that want structure out of the box.
Framework choice matters less than team familiarity and hiring pipeline. A mediocre framework your team knows beats a perfect one nobody can maintain.
Accessibility in SPAs
Client-rendered apps often fail accessibility audits because focus management breaks on route changes. When the "page" changes without a reload, screen readers may not announce the new content. Fix this by:
- Moving focus to the main heading on navigation.
- Using semantic HTML (
<main>,<nav>,<button>) instead of clickable<div>elements. - Testing with keyboard-only navigation and automated tools like axe.
Accessibility is not a polish item — it affects legal compliance and usability for every user on a phone with a cracked screen and no mouse.
Deployment and hosting
SPAs ship as static assets. Host the built dist/ folder on S3 + CloudFront, Vercel, Netlify, or any CDN. Configure your server to return index.html for unknown routes so client-side routing works on direct URL visits.
Set cache headers carefully: long cache for hashed asset files, short or no cache for index.html so users receive new bundles after deploys.
Further Reading
Discover more articles on similar topics across our network
Java for Web and Mobile Development: Frameworks, Architecture, and Use Cases
Stackademic



Comments
Loading comments…