← All posts
7 min read

Single-Page Applications: Browser-Resident Applications With Client Routing

#technology#single-page-applications#spa#web-development
📑 On this page

Traditional websites commonly request a new HTML document for each navigation.

A single-page application, or SPA, keeps an application runtime active in the browser and changes views without fully reloading the surrounding document.

A SPA moves routing, rendering, data fetching, and substantial application state into browser JavaScript.

This can create fluid interaction. It also makes the browser responsible for more architecture.

A concrete example: web email

An email web app loads:

  • Navigation
  • Folder list
  • Message list
  • Reading pane
  • Composer

Selecting another folder:

  1. Updates the URL.
  2. Fetches messages.
  3. Replaces the list.
  4. Preserves the surrounding interface.

Music playback, draft text, and open panels can remain active.

A full document reload for every message would be possible, but a SPA better supports this long-lived workspace.

The application shell

The first response often contains:

  • Basic HTML
  • CSS
  • JavaScript bundles
  • Loading shell

The browser starts the application, reads the current URL, and renders the matching view.

Initial performance depends on:

  • Bundle size
  • Network
  • JavaScript parsing
  • Framework startup
  • First data request

A tiny HTML shell does not mean a fast first experience.

The shell should expose useful loading structure and avoid a blank screen.

Client-side routing

A client router maps URLs to views:

/inbox
/messages/42
/settings/profile

It uses the browser history API so navigation updates the address without a full reload.

Good routing preserves:

  • Deep linking
  • Refresh
  • Back and forward
  • Shareable URLs
  • Correct document titles
  • Focus and scroll behavior

If refreshing /messages/42 returns a server 404, the deployment has not been configured to serve the SPA route.

Data comes through APIs

SPAs fetch data after or during navigation:

GET /api/messages?folder=inbox

The UI must represent:

  • Loading
  • Empty
  • Error
  • Stale data
  • Refresh
  • Offline

Several requests may race when users navigate quickly.

Cancel obsolete requests or ignore stale responses so an earlier slow request does not overwrite the current screen.

State lives longer

Because the application remains loaded, state can persist across views:

  • Signed-in session
  • Draft
  • Selected filters
  • Cached data
  • Open dialogs
  • Optimistic changes

Long-lived state creates consistency challenges.

The server may change while the tab remains open for hours.

Applications need cache invalidation, background refresh, version handling, and session-expiration behavior.

Reloading occasionally hides bugs; architecture should not depend on it.

Code splitting

One enormous JavaScript bundle makes users download code for features they may never open.

Code splitting loads route or feature chunks on demand.

Benefits:

  • Smaller initial download
  • Less parsing and execution

Costs:

  • Navigation may wait for a chunk.
  • Deployment can remove an old chunk while a long-open tab requests it.
  • More requests and caching complexity

Prefetch likely routes and handle chunk-load failure by offering a safe refresh.

Client caching

SPAs often cache API data for responsiveness.

The cache needs:

  • Stable keys
  • Freshness policy
  • Deduplication
  • Mutation invalidation
  • Error handling
  • Garbage collection

Server state and UI state are different.

Server state is a cached copy of remote truth. UI state includes local choices such as an open menu.

Treating both as one global object can make updates and ownership confusing.

Optimistic updates

An SPA can update immediately before confirmation.

For marking a message read:

  1. Update local state.
  2. Send request.
  3. Confirm or roll back.

This makes interaction feel fast.

The design must account for:

  • Request failure
  • Duplicate action
  • Conflicting server update
  • User navigating away

For high-impact actions, show pending state and wait for authoritative confirmation.

Accessibility during client navigation

Full-page navigation normally gives assistive technologies a new document context.

SPA navigation must recreate important behavior:

  • Update title
  • Move focus to the main heading or appropriate target
  • Announce loading and errors
  • Preserve keyboard order
  • Avoid trapping focus

Visual content change alone may be invisible to screen-reader users.

Use semantic HTML and route-level accessibility tests.

Framework routing does not make navigation accessible automatically.

Scroll restoration

Users expect:

  • New route to begin appropriately
  • Back navigation to restore prior scroll
  • In-page links to reach targets

SPAs need scroll-restoration policy.

Always jumping to top can harm list-detail workflows. Always preserving position can open a new page halfway down.

Behavior should follow navigation intent:

  • New content
  • History traversal
  • Modal route
  • Filter update

Test on mobile where browser chrome and virtual keyboards affect viewport.

Error boundaries and recovery

A JavaScript error in one component should not destroy the entire app.

Error boundaries or equivalent structures can:

  • Isolate failure
  • Show fallback
  • Record diagnostics
  • Offer retry

They do not catch every error type or repair corrupted state.

For critical workflows, preserve draft input and provide a full reload or alternate path.

A SPA is one long-running process; local containment matters.

Deployment and stale clients

A user can keep a tab open across several deployments.

The client may call:

  • New API from old code
  • Old endpoint after removal
  • Chunk URL no longer available

Use:

  • Backward-compatible APIs
  • Long-lived hashed assets
  • Version detection
  • Graceful upgrade prompts
  • Service-worker update control

Do not force-refresh during an unsaved form or transaction.

Coordinate update timing with user state.

Authentication and security

SPAs run in an untrusted browser.

Risks include:

  • Cross-site scripting
  • Token theft
  • Cross-site request forgery with cookies
  • Malicious dependencies
  • Sensitive data in local storage

Use output encoding, content security policy, secure session design, dependency review, and server-side authorization.

Never embed private API secrets.

JavaScript source and network requests are visible to the user.

Search and social sharing

Public SPA content may need server or static rendering for:

  • Search discovery
  • Link previews
  • Fast first content

Modern hybrid frameworks can render public routes on the server while preserving SPA navigation after load.

An authenticated internal tool may not need search indexing.

Do not add server rendering solely because SPAs are said to have SEO problems when the content is private.

Match architecture to audience.

Offline and installability

Service workers can cache assets and intercept requests.

A progressive web app may support:

  • Installation
  • Offline shell
  • Background synchronization
  • Push notifications

Offline data and actions require explicit conflict and update rules.

Caching the shell alone can produce an app that opens offline but cannot do anything.

Do not label a product offline capable without testing real workflows under lost and intermittent connectivity.

Memory and resource use

A SPA can stay open all day.

Problems include:

  • Event listeners not removed
  • Timers continuing
  • Cached data growing
  • Detached DOM nodes
  • Large media objects retained

Measure memory over long sessions, not only page startup.

Clean up subscriptions on component removal and bound caches.

Mobile browsers may terminate resource-heavy tabs.

SPA, multi-page, and hybrid

A multi-page application requests a new document for navigation.

Benefits:

  • Simpler lifecycle
  • Natural browser behavior
  • Less client state
  • Strong progressive enhancement

SPAs fit rich long-lived workspaces.

Hybrid applications use server-rendered routes and client transitions or interactive islands.

The useful question is not "SPA or website?" It is which interactions need a persistent browser runtime and what cost that introduces.

Knowledge check

  1. What responsibilities move into the browser in a SPA?
  2. Why must the server support deep-linked SPA routes?
  3. How does server-state caching differ from local UI state?
  4. What accessibility behavior must client-side navigation recreate?
  5. Why can long-open tabs cause deployment compatibility problems?

The one idea to remember

A SPA is a browser-resident application with client routing, data fetching, and long-lived state. Its fluid experience comes with responsibility for loading, accessibility, cache consistency, failure recovery, security, and old clients that outlive deployments.