100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C#

Deploying Blazor Apps

How to publish and deploy Blazor WebAssembly and Blazor Server apps to production, including hosting choices, compression, and configuration.

Practical BlazorIntermediate10 min readJul 10, 2026
Analogies

Choosing a Hosting Model Before Deployment

Deployment strategy depends heavily on which hosting model you built: a Blazor WebAssembly (WASM) app publishes to static files, a .dll-and-.wasm payload plus a service worker, that can be served from any static file host or CDN with no .NET runtime required on the server, whereas Blazor Server keeps all component state and rendering on the server and pushes UI diffs to the browser over a persistent SignalR connection, meaning the deployment target must be a real ASP.NET Core process capable of holding long-lived WebSocket connections. Since .NET 8, Blazor Web Apps let you mix render modes per component (Static Server, Interactive Server, Interactive WebAssembly, or Interactive Auto), so a single deployment might need both a running server process and a client-downloadable WASM bundle, which changes the deployment checklist compared to a pure single-mode app.

🏏

Cricket analogy: A Test match unfolds live over five days with constant back-and-forth with the crowd, like Blazor Server's persistent SignalR connection, while a recorded highlights reel can be watched anywhere without needing the live stadium connection, like a WASM app running fully client-side.

Deploying Blazor WebAssembly to Static Hosting

Running dotnet publish -c Release on a Blazor WASM project produces a bin/Release/net8.0/publish/wwwroot folder containing static assets ready to be served as-is by any static file host, Azure Static Web Apps, GitHub Pages, Netlify, an S3 bucket behind CloudFront, or an nginx container, with no need for a .NET runtime on the server since the app runs entirely in the visitor's browser. Because the framework files (blazor.boot.json, .dll assemblies, and the WASM runtime itself) can be sizable, production hosts should serve them with Brotli or gzip compression; the .NET SDK's publish step already generates precompressed .br and .gz variants alongside the originals, and most static hosts and reverse proxies will serve those automatically if configured to prefer precompressed content over compressing on the fly.

🏏

Cricket analogy: Shipping a full training kit to an academy once, rather than couriering equipment before every single session, mirrors deploying static WASM files once to a CDN rather than needing a live server process per request.

Reducing WASM Payload and Load Time

Blazor WASM's initial download can be large because it ships the .NET runtime, the app's assemblies, and referenced framework libraries, so production apps should enable the trimmer (on by default in Release builds for WASM) to strip unused code, consider Ahead-of-Time (AOT) compilation with <RunAOTCompilation>true</RunAOTCompilation> for CPU-heavy apps at the cost of a larger download but faster execution, and use lazy loading via <BlazorWebAssemblyLazyLoad> to defer downloading assemblies for rarely-visited routes until they're actually navigated to. Enabling compression at the host and confirming the browser's Network tab shows .wasm and .dll files served with a br or gzip Content-Encoding header is worth verifying explicitly after every deployment, since a misconfigured host silently falling back to uncompressed transfer can multiply first-load time.

🏏

Cricket analogy: A touring squad only brings the specific gear needed for the conditions of each ground instead of hauling every piece of equipment to every match, mirroring the WASM trimmer stripping unused code from the shipped bundle.

Deploying Blazor Server and Interactive Server Apps

Because Blazor Server maintains per-user state and an active SignalR circuit on the server, deployment targets like Azure App Service, a Kubernetes cluster, or a VM behind nginx must be configured for WebSocket support and, if running multiple server instances behind a load balancer, either sticky sessions (client affinity) so a user's requests keep hitting the same server instance that holds their circuit, or a distributed backplane such as Azure SignalR Service that lets circuits survive being routed to different backend instances. Publishing a Blazor Server app produces an ordinary ASP.NET Core executable, so containerizing it with the official mcr.microsoft.com/dotnet/aspnet base image and running it behind a reverse proxy configured with Connection and Upgrade headers passed through correctly for WebSocket upgrade requests is the standard production setup.

🏏

Cricket analogy: A player's entire innings, guard marks, and scoring pattern stay tied to that one specific crease position throughout their innings, mirroring how a user's Blazor Server circuit must stay tied to one specific server instance unless a backplane like Azure SignalR Service is in play.

dockerfile
# Dockerfile for a Blazor Server (or Blazor Web App with Interactive Server) deployment
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish ./src/BlazorApp.csproj -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 8080
ENV ASPNETCORE_URLS=http://+:8080
ENTRYPOINT ["dotnet", "BlazorApp.dll"]

# nginx reverse proxy snippet enabling WebSocket upgrade for SignalR
# location / {
#     proxy_pass         http://localhost:8080;
#     proxy_http_version 1.1;
#     proxy_set_header   Upgrade $http_upgrade;
#     proxy_set_header   Connection "upgrade";
#     proxy_set_header   Host $host;
# }

For Blazor WASM apps hosted on a platform that doesn't natively understand SPA fallback routing (serving index.html for any unmatched path so client-side routing works), you must configure a rewrite rule; Azure Static Web Apps, Netlify, and GitHub Pages (with a 404.html trick) each have their own mechanism for this, and skipping it causes deep-linked routes to 404 on a hard refresh.

Deploying a Blazor Server app behind a load balancer without either sticky sessions or a SignalR backplane will intermittently break the app for users whose requests get routed to a different server instance mid-session, since that instance has no knowledge of their existing circuit; the symptom typically looks like random 'Attempting to reconnect' banners or a full page reload prompt.

  • Blazor WASM publishes to static files servable by any static host or CDN with no server-side .NET runtime required.
  • Blazor Server requires a running ASP.NET Core process with WebSocket support for its persistent SignalR circuit.
  • .NET 8+ Blazor Web Apps can mix render modes, so a single deployment may need both a server process and a WASM bundle.
  • Enable Brotli/gzip compression and verify Content-Encoding headers on .wasm and .dll assets after every deployment.
  • Use the trimmer, optional AOT compilation, and lazy loading to reduce WASM initial payload size.
  • Blazor Server behind a load balancer needs sticky sessions or a backplane like Azure SignalR Service to keep circuits alive.
  • Configure SPA fallback routing on static hosts so deep-linked client-side routes don't 404 on refresh.

Practice what you learned

Was this page helpful?

Topics covered

#BlazorStudyNotes#MicrosoftTechnologies#DeployingBlazorApps#Deploying#Blazor#Apps#Choosing#StudyNotes#SkillVeris#ExamPrep