What is Blazor?

Blazor is Microsoft's hot new full-stack web framework for .NET. Though it was released several years ago now, I think it still deserves the new qualifier at the time of writing this in 2023 because it's still going through a lot of churn and finding its place within the plethora of existing web framework options out there.

Microsoft does also have a recent track record of releasing things before they're truly mature enough for production use.

I've been running Blazor Server in production for quite a few years with great results, and have been increasingly using it for a number of professional and personal projects. However when it came to building this personal website in 2023, I originally chose to opt for the simpler server-side-only .NET Razor Pages framework which I considered to be more suitable for a mainly static website - albeit with some minimal dynamic server-side functionality.

I knew that I wanted to have a server-side app framework and not just a pre-compiled static site due to some interactive features I had planned. And I chose not to go down the route of a separate back-end API with a JS front-end, because just having one deployable artefact for this site was enough complexity for what is essentially a small side-project.

One of the reasons for going with Razor Pages for this website was because Blazor (pre .NET 8) - as good as it was - had some downsides. For the Blazor Server variant, it relied on a constantly maintained connection with the server for its interactivity (usually over a websocket, via Microsoft's SignalR framework), and each website visitor session is maintained server-side, with an associated memory/performance overhead. It can be really great for a line-of-business application with a predictable audience size, but perhaps less suitable for a public facing static website with a volume of traffic which might be a little more unpredictable. Especially so if you plan to introduce things like load balancing - which while not impossible with Blazor Server, adds some additional complexity.


To cut to the chase, this site is now running on Blazor, and is load balanced - something that was made easier by the new features introduced in .NET 8, which I'll come on to...


One of the things I really like about Blazor Server though is how productive you can be when building with it. With .NET's hot reload capabilities via dotnet watch I found that I could put together prototype apps with rich server-side functionality - which still felt as snappy as a SPA app - in a really short space of time. It's a really excellent framework for prototypes and MVPs, and in my experience for larger production apps too. Plus, the performance hit of maintaining sessions on the server can sometimes be overstated - I've actually gotten surprisingly good performance out of pretty minimal hosting infrastructure using Blazor Server. And it's possible to make the client-side reconnection logic (in the event that the persistent connection drops) a lot more graceful and seamless than the default out-of-the-box behaviour - which has been another common complaint about Blazor Server. That said, I really think it excels in scenarios where your traffic is not "spikey". Internal facing apps or small/medium SaaS apps are fine. Large public facing media or ecommerce websites with potential surges of traffic - perhaps not so much.

Blazor WebAssembly on the other hand - the other variant of Blazor available prior to .NET 8 - has its own downsides. As amazing as current developments are in the world of WebAssembly in the browser, Blazor WebAssembly suffered from an inevitable initial "lag" as assets are initially downloaded, with various clever workarounds available - but nonetheless, countering this lag required a few "gymnastics". Mix into that some additional challenges around client-side caching and the fact that you now most likely have .NET code running in both the client and on the server, and the compromises of Blazor WebAssembly are significant enough that, in my opinion, you would only want to use it in very specific scenarios. The most obvious being rich and highly interactive client apps, say something like a Google Docs equivalent, or perhaps where data privacy is important and you want to do client-only processing, or lastly for functionality that relies on advanced client-side code which would be otherwise difficult to achieve in other client frameworks.

One of the other clear benefits of Blazor WebAssembly is the consistency of tooling across front-end and back-end code and the options for code reuse. You can have C# running in both the client and the server! But then, you have... um... C# running on both the client and server... The "code reuse" story is not quite as utopian as it sounds. In my view, having blurred lines between code that runs client side and server side is a security foot-gun just waiting to go off.

So, for the purposes of building this website, I went with the much simpler Razor Pages, which is a much more traditional - some might say old school - server-side only framework. It renders each page once and delivers it to the client in a single request (imagine that! The sheer audacity...). In that respect it's not that much different from something like PHP. For my purposes at the time, I liked its simplicity and easy ability to scale as necessary for a public facing "largely static" personal website.

Everything has changed with Blazor in .NET 8

Blazor in .NET 8 is a significant step forwards from what came before. Not only have a lot of the above compromises been addressed, but newly added features open up the framework to a much wider set of use-cases. So much so that I believe .NET 8 Blazor is almost the definitive Blazor - it's what it should have been from the start (with some caveats which I'll get onto).

Blazor is quickly becoming my favourite .NET-based web framework ever.

The lines between Server and WebAssembly have been blurred - your apps can now contain a mix of the two if you're feeling brave - but, the biggest improvement in my opinion is the introduction of the new static server-side rendering model (static SSR) with Enhanced Navigation and Streaming Rendering.

Static Server-Side Rendering (SSR)

The new Static SSR and Enhanced Navigation features allow you to do away with the persistent websocket requirement of Blazor Server in many cases, in favour of a more traditional server-side rendered page model - akin to Razor Pages - but with some added lightweight javascript which enhances the app to automagically give it a SPA-like feel.

In the simplest sense, Blazor static SSR with enhanced navigation is very similar to Razor Pages but with some added client-side routing which intercepts all page navigation events and handles them in a more intelligent way. Though you can navigate directly to any URL in your app and receive a straightforward server-side rendered page - which is a must from an SEO point of view - with the JS-based enhanced navigation, once that page is loaded, all subsequent navigation events within the same browser tab are processed by Blazor's Javascript and fetched asynchronously instead. When you click on a link to another page in your app, this minimal front-end routing logic calls the server to render the new HTML for the page you're about to navigate to, but instead of causing a full page refresh, it simply patches only the part of the DOM that needs to change. So as an example, if you have a consistent header across all your pages, the header markup doesn't get touched.

The benefit of all this is a much snappier experience, with page loads that feel like you're using a SPA - but without you having to do anything to actually build your site like a SPA. To see this in action you can try it right now on this website. As long as you have Javascript enabled, navigating to a different page on my site will do an in-place update of only the changed DOM elements, and not a full page load. I wrote zero Javascript to make that happen. It's all Blazor.

And if you don't have Javascript enabled? It still just works like a normal "static" site.

This progressive enhancement of page navigation behaviour with in-place DOM updates is similar to the Boosting feature in Htmx - another up and coming web framework that I'm keeping an eye on. Though the Htmx version is a little more simplistic and just targets the body tag by default. The nice thing about Blazor's implementation is that the mechanics on both the client and the server are completely handled for you out of the box.

Streaming Rendering

On top of Static SSR and enhanced nav, with Streaming Rendering you can go one step further and stream multiple updates to a page sequentially while processing is still happening on the server, allowing you to easily display things like loading indicators or placeholders for content while the server is still processing the request. Without needing to write any client-side code.

Enhanced Forms

Forms benefit from enhanced functionality too, with simple form posts being able to be handled by the same client-side routing - allowing for partial DOM updates on form posts, to show results screens or validation messages etc. (If you want to shoot me a message, you can see this in action on my contact page!)

Interactive rendering modes

Only when you need more complex interactive functionality do you need to venture into the more advanced scenarios of interactive rendering modes, like Interactive Server Rendering (akin to Blazor Server from prior to .NET 8), with its SignalR websocket connections or Blazor WebAssembly, running code in the client. And even then, you can now selectively make only individual components on a page interactive, while keeping the rest of the page using the simpler server-side with enhanced nav model.

So for example, if you have a component within your page which needs richer, more dynamic functionality, you can render this using the Blazor interactive server model (where a persistent SignalR connection is automatically created in the background) and use this for rich interactive functionality with realtime server-pushed updates, while keeping the rest of your site using the simpler lighter weight approach.

The maturing of Blazor

In my view this is getting close to a best of all worlds framework which is becoming extremely versatile. There are still cases where I would go for a more "traditional" SPA architecture, perhaps with something like Vue.js or Svelte on the front end and .NET WebAPI on the backend - but in most cases going forwards, I can see myself reaching for Blazor as my primary/default choice because of this versatility and the speed of development that comes with only needing to build for one side of the network connection.

SPA frameworks were developed for their rich client-side interactivity, responsiveness and scalability. But building separate client and server components is always going to be more complex than just building for the server alone (or indeed just building for the client alone in the case of static precompiled sites). With Blazor bringing some of these SPA-like benefits to what is still primarily a server-side framework - there are fewer reasons to build and maintain separate tech stacks for client and server if you're already working in the .NET ecosystem - especially for smaller apps, internal facing apps, or prototypes.

The caveat

Now for a slight caveat...

Microsoft introduced another feature in .NET 8 Blazor, ostensibly to deal with the often reported issue of upfront latency of WebAssembly apps due to the initial hit of needing to download a bunch of binaries. The new "Interactive Auto" rendering mode uses some magic to allow you to make specific components able to run both server-side and client-side.

The idea is that the component is initially rendered using the Server interactivity model, complete with persistent websocket connection, while the WebAssembly equivalent of the component downloads in the background. The browser then switches to using the WebAssembly version of the component once it has booted up.

I don't really like this idea.

Mixing and matching different components on the same page with different interactivity models (some WebAssembly, some Server) already seemed to me like something where you'd want to exercise quite a bit of caution. But to make the same component be designed to run its code both server-side and client-side seems to me to not just be a potential foot-gun but a foot-bazooka. It feels like a "because we could" feature which is a compromise to try and counter the upfront loading cost of WebAssembly binaries. But to me it just takes an existing awkward problem and makes it even worse by adding additional complexity and too many "moving parts". Maybe it demos well, but I'm not sure that it's a good idea architecturally.

I believe that the static SSR, Enhanced Navigation and Streaming Rendering features of Blazor in .NET 8 are the true stars of the .NET 8 show, combined with being able to punch holes in a page for more advanced interactive components where needed. These features are so exciting and such a big improvement to Blazor's overall model, that I will happily overlook the aspects of this update which don't feel quite so well advised!

So what of WebAssembly?

To me, WebAssembly still feels like it sits a little awkwardly within the Blazor story. Initially it seemed to be the flagship feature of Blazor, but it's never quite worked as smoothly as I would have liked. I suspect it will continue to mature and become easier to work with, but I have no desperate desire to use it yet.

At the time of writing, if I had to pick a more client orientated stack, I'd still likely opt for a more traditional JS framework with a .NET WebAPI backend - in most cases. In fact I'm quickly becoming a proponent of frameworkless client-side development with just pure JS, enabled by the maturing of the Web Components standard, JSDoc and excellent build tools like Esbuild which don't rely on Node.js. I've also had great results with sprinkling some light touch client-side Javascript functionality on top of Blazor Server apps using lightweight frameworks like Alpine.js or Htmx. (The latter is something I wouldn't advise doing on a whim - it's important to understand the implications of how these frameworks intersect with the DOM manipulation that Blazor Server is itself doing, but if you're careful, it can lead to excellent results and a further offsetting of Blazor Server's slightly heavier (server) memory/performance overhead.)

Blazor (server)'s JS interop is also improving, with support now for importing native ECMAScript JS modules - something which I've been making a lot more use of recently.

In other words, I'm finding that there are sufficient options for layering client-side interactivity on top of Blazor's server-based interactivity models, that I'm not finding strong reasons to bite the bullet and just go for full Blazor WebAssembly on the client. Perhaps that will change as things develop further in the future.

.NET for web is still going strong

I've always had a soft spot for developing with .NET for the web. I've worked with pretty much every incarnation of it over the years. There has been a lot of churn, a lot of disruption - especially for teams who got caught in the gap during the transition from .NET Framework to .NET Core - and a few missteps, but even 20+ years on from .NET's original release, I am still extremely bullish about the ecosystem.

I'm enjoying developing with .NET more so than ever.

It's keeping up with the pace of development seen in other web frameworks which have been around a tenth of the time. The steady cross-platform push which started with .NET Core is keeping it fresh - I probably wouldn't still be a .NET developer if not for that - and combined with superb tooling and a really solid and extensive base library of APIs, the ecosystem is an incredibly strong one for web development in 2024 and beyond.

I just hope that Microsoft keeps the Windows product managers away from it.