Client-Side First: Building Modern SPAs on Azure Static Web Apps

Introduction — What “Client-Side First” Means

Over the last decade, web development has seen a shift in who’s doing the heavy lifting — the server or the browser. Traditionally, web pages were rendered on the server: every time a user clicked a link, the server would generate a new HTML page and send it back to the browser. This approach, known as Server-Side Rendering (SSR), made it easy for content to be indexed by search engines and guaranteed users always got a fully formed page — but it also meant slower navigation, more network traffic, and constant reloads.

Today, that pattern is being challenged by modern JavaScript frameworks and WebAssembly-powered tools that allow the browser itself to take the lead. This model is called Client-Side Rendering (CSR) — where instead of receiving fully rendered pages from the server, users are served a minimal HTML shell and the rest of the experience is powered by JavaScript or WebAssembly running in the browser.

Once loaded, the application takes control: it handles routing, UI rendering, and state updates directly in the browser without requiring a full page reload. You’ve probably experienced this already — clicking around apps like Gmail, Trello, or GitHub, you’ll notice the interface updates instantly, without refreshing the page. That’s CSR at work.

This “client-side first” mindset is at the heart of most Single Page Applications (SPAs). They offer speed, interactivity, and flexibility — but they also come with trade-offs and require proper configuration when deployed, especially on static hosting platforms that don’t understand dynamic routes by default.

Understanding how CSR works under the hood — and how to host it correctly — is crucial for modern frontend development. That’s where services like Azure Static Web Apps come in, and where this post begins.s.

Static Hosting ≠ Static Experience

In modern web architecture, the term “static web app” might sound limiting — but it’s anything but. Whether you're building a React application with JavaScript or a Blazor WebAssembly application with .NET, the resulting app can be delivered as a static web app. In fact, static web apps are often just SPAs deployed on a CDN.

A Single Page Application (SPA) — like those built with React, Vue, or Blazor WebAssembly — fits perfectly into the static web hosting model. Once compiled, these apps consist of static assets: an index.html, bundled JavaScript or WebAssembly files, stylesheets, and other resources. These are then served by platforms like Azure Static Web Apps, Netlify, or Vercel, without the need for a server to dynamically generate pages.

From a hosting perspective, the site is static. But from a user’s perspective, the experience is dynamic.

Once the app is loaded into the browser:

  • JavaScript-based SPAs (like React) bootstrap the app using the browser’s JS engine.

  • Blazor WebAssembly SPAs download a WebAssembly-powered .NET runtime and execute C# assemblies directly in the browser.

In both cases, the browser becomes the primary rendering engine. Navigation is handled client-side, state is maintained without reloads, and updates are performed in real time — all without server-rendered pages.

The beauty of this architecture lies in its ecosystem flexibility:

  • If you're coming from a JavaScript background, you might use React + Vite, deploy the build folder, and call it a day.

  • If you’re in the .NET world, Blazor WebAssembly gives you the same SPA model, but powered by C# and .NET running via WebAssembly.

This makes “static web app” and “SPA” practically interchangeable when talking about client-side-first experiences deployed on static infrastructure.

And while the backend is removed from the rendering process, dynamic behavior is preserved through API interactions, serverless functions, and real-time updates — all happening from the client.

So yes, the platform serves static files. But the browser turns those files into an application — fast, interactive, and stateful. In the static hosting model, the “static” refers to the delivery mechanism, not the user experience.

What Is Client-Side Rendering (CSR)?

Client-Side Rendering (CSR) is an architectural approach where the browser — not the server — is responsible for rendering the user interface. Instead of receiving a fully-formed HTML document for each page request, the browser downloads a minimal HTML shell, along with JavaScript (or WebAssembly), which then dynamically constructs the UI and handles navigation.

Here’s a simplified lifecycle:

CSR is the default rendering model for most modern front-end frameworks:

  • React, Vue, and Angular rely on the browser’s JavaScript engine to manipulate the DOM.

  • Blazor WebAssembly compiles .NET code into WebAssembly, running the rendering logic directly in the browser.

This rendering model offers a fast, app-like experience after the initial load. Transitions are smooth, client-side state is preserved, and requests to the backend (if any) are often made asynchronously via fetch or HTTP clients.

However, CSR also introduces trade-offs:

  • SEO can be a challenge, since search engine bots may not execute JavaScript.

  • Initial load time may be longer, especially for larger bundles.

  • Fallback routing must be configured manually, since the browser doesn't hit real file paths — a topic we’ll explore next in the context of Azure Static Web Apps.

Ultimately, CSR is about delegating responsibility to the browser — treating it as a full runtime environment capable of rendering, updating, and managing your application independently.

Client-Side Rendering vs Server-Side Rendering

In short, Client-Side Rendering (CSR) puts the responsibility of rendering content in the browser, while Server-Side Rendering (SSR) generates HTML on the server before sending it to the user. CSR loads faster after the initial visit and feels more like an app, but SSR is often preferred for pages that require fast SEO indexing or initial content visibility. The two serve different goals — CSR focuses on interactivity and speed, SSR prioritizes first-paint performance and accessibility to search engines.

CSR vs SSR – At a Glance

FeatureClient-Side Rendering (CSR)Server-Side Rendering (SSR)
Rendering happens inThe browserThe server
Initial page loadLoads minimal HTML, then hydratesFull HTML is delivered on request
Navigation experienceFast, smooth transitions (JS-controlled)New page loads on every route (or hybrid)
SEO readinessLimited (needs JS execution)Excellent (HTML visible immediately)
Tooling examplesReact, Vue, Blazor WebAssemblyNext.js, Nuxt, ASP.NET MVC, Blazor Server

Solving the CSR Pain Points

Client-side rendering brings a lot to the table: speed after load, seamless routing, and app-like interactivity. But it also introduces a few architectural quirks — especially when deployed to static hosts. These quirks aren’t dealbreakers, but they do require thoughtful handling.

One of the most common is search engine visibility. Since content is rendered in the browser via JavaScript or WebAssembly, crawlers may not see anything useful unless they’re able to execute scripts. This can impact indexing and discoverability for routes that matter — like landing pages or documentation.

Another concern is performance during first load. While SPAs feel fast after hydration, initial download sizes can be large due to bundled JavaScript or .wasm payloads, especially when using frameworks like React or Blazor WebAssembly.

And finally, there’s routing. Because static hosts don’t understand client-defined routes, direct navigation to paths like /tasks/active will often result in a 404 unless you’ve accounted for it. (We’ll look at exactly how to fix this next.)

These aren’t new problems, and modern tooling provides several ways to mitigate them:

  • SEO: Pre-render key routes during build time or use dynamic metadata injection (react-helmet, Blazor’s HeadOutlet) for improved crawlability and sharing.

  • Performance: Adopt code-splitting, lazy-loading, and compression to minimize load time without sacrificing functionality.

  • Routing: Static platforms like Azure and Netlify support fallback routing — but it’s up to you to configure it correctly.

Handled well, these trade-offs become invisible to your users. Client-side rendering, despite its quirks, remains a powerful and scalable model — especially when paired with a smart deployment setup.

Real World Routing: How Azure Static Web Apps Handles This

One common challenge when deploying SPAs to static hosts like Azure Static Web Apps is client-side routing. Frameworks like React, Vue, and Blazor WebAssembly use internal routing — meaning the browser manages navigation without requesting new HTML pages. But on a static host, if a user directly visits a route like /tasks/active, the server will look for a physical file at that path. If none exists, it returns a 404.

To resolve this, Azure supports fallback routing, which lets you reroute all unmatched paths to your SPA’s entry point (index.html). From there, the JavaScript or WebAssembly router takes over and displays the correct view.

Here’s what a basic staticwebapp.config.json file looks like with a fallback rule:


 {
  "navigationFallback": {
    "rewrite": "/index.html",
    "exclude": ["/api/*", "/images/*", "/css/*", "/js/*"]
  }

This tells Azure: “If the route doesn't match a static file, serve index.html and let the client figure out what to render.”

🧭 How SPAs Handle This Internally

  • React (React Router): React apps use react-router-dom to map URLs to components on the client. Once the app loads, route changes are handled without server requests.

  • Vue (Vue Router): Similar mechanism — Vue Router intercepts navigation events and renders views inside the app shell.

  • Blazor WebAssembly: Uses the built-in Router component. Once the app is hydrated, it parses the URL and loads the correct Razor component without a server call.

Regardless of the framework, the goal is the same: ensure all routes point to a single entry file, and let the client-side router do the rest.

Is The Future is Client-Side First?

Client-side rendering is undeniably a powerful and scalable model — especially in a world where performance, interactivity, and developer experience are key. It allows teams to ship fast, dynamic applications with minimal infrastructure, making it ideal for dashboards, admin panels, internal tools, and rich user interfaces that don’t rely heavily on SEO or immediate content visibility.

But like most things in software, it depends.

If you're building a marketing site, an e-commerce homepage, or a content-heavy platform where first paint speed and SEO are critical, server-side rendering (SSR) or static site generation (SSG) might still be your best bet. These strategies deliver fully rendered HTML straight from the server (or at build time), ensuring that content is visible instantly — both to users and search engines.

In contrast, client-side rendering (CSR) is best suited when:

  • Your users are logged in most of the time.

  • The app fetches data dynamically.

  • SEO isn't your top concern.

  • You want fast, seamless navigation without full page reloads.

Ultimately, the web is flexible enough to support all these patterns — often even within the same project. What matters most is choosing the rendering model that fits what you're building, not just what’s trending.

A Little App You Can Try

And of course — I wouldn’t be a dev girlie if I didn’t have an app to tie it all together.
If you’ve been wondering why I kept referencing /tasks/active, it’s from my own client-rendered task manager, built and deployed with Azure Static Web Apps

👉 Try the app here — it’s a focused project that puts everything we’ve explored into practice, with additional features like authentication and authorization using JWT tokens, protected views, and cached services for efficient client-side state management using Blazor Webassembly ans azure serveless function.

Next time, I’ll be diving into static site generation and server-side rendering using frameworks like Next.js — comparing the experience, the trade-offs, and sharing what I’ve learned building apps across both approaches.

References

  • Azure Static Web Apps Documentation – Configuration
    👉 https://learn.microsoft.com/en-us/azure/static-web-apps/configuration

  • Azure Static Web Apps – Routing and Authorization
    👉https://learn.microsoft.com/en-us/azure/static-web-apps/routes

  • Microsoft Docs – Build Your First Blazor WebAssembly App
    👉 https://learn.microsoft.com/en-us/aspnet/core/blazor/get-started?view=aspnetcore-8.0

  • React Router – SPA Routing Guide
    👉 https://reactrouter.com/en/main/start/tutorial

1
Subscribe to my newsletter

Read articles from Mayowa Oladimeji directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mayowa Oladimeji
Mayowa Oladimeji

Software Engineer | React, JavaScript, C#| Passionate About Building Responsive, Accessible and Scalable Software Solutions