The actual question asks two different things and requires a very long answer.
There are several patterns that can be used, eg MVVM, MVU. Blazor WebAssembly is roughly React# so using the same component logic used in React helps a lot.
Both frameworks build SPAs, so the concerns are the same, so the solutions are similar. And just like all SPA frameworks, MVC was replace by MVVM almost a decade ago with eg Backbone. State management between multiple components emerged as a separate concern so SPAs have different patterns and mechanisms to manage state it (think React's Redux and alternatives).
And even storage is non-trivial. ASP.NET Core Blazor state management describes storage in multiple places:
- A server database
- Query parameters
- Browser local storage
- In-memory caches
Multiple patterns can be used - React-like components with the master state held in a ViewModel at the "parent" level, wherever that may be.
In Blazor's data binding, like React, data and state flow downwardsfrom the parent through component Parameter
properties. Changes to the data flow upwards through EventCallback
s. That makes implementing patterns like MVVM and MVU easy.
Component-level design
In React (and Blazor), data and state flow downwards from the parent. Changes to the data flow upwards. Blazor's data binding is built to facilitate exactly this, although it doesn't restrict yo:
- The actual state is held by the parent, in whatever form the parent wants. It may be multiple properties, a model/DTO class or a ViewModel that follow. The data is passed to nested components through component
Parameter
properties.
- Changes, eg in response to events are signaled through
EventCallback
s. The nested properties don't store the changed data themselves though.
In this example copied from the docs, the ChildBind
component never changes the Year
property itself. It tells its parent the year changed, and leaves it to the parent (and data binding) to tell it what to redraw :
Shared/ChildBind.razor
<div class="card bg-light mt-3" style="width:18rem ">
<div class="card-body">
<h3 class="card-title">ChildBind Component</h3>
<p class="card-text">
Child <code>Year</code>: @Year
</p>
<button @onclick="UpdateYearFromChild">Update Year from Child</button>
</div>
</div>
@code {
private Random r = new();
[Parameter]
public int Year { get; set; }
[Parameter]
public EventCallback<int> YearChanged { get; set; }
private async Task UpdateYearFromChild()
{
await YearChanged.InvokeAsync(r.Next(1950, 2021));
}
}
It's possible to bind across more than 2 components with a bit of work or by using Cascading values and parameters.
Application architecture - Overview
The obvious way to design a complex SPA both in React and Blazor is to compose components. Both frameworks are built to work that way. What's not so obvious is how to move data/state and events among those components, who's going to store the data, who's going to change it, how changes end up modifying the UI etc.
And since we talk about SPAs, even the "where" has no clear answer, with state kept in query parameters, browser storage or remote services.
Picking an architecture depends on the problem that needs solving. There's no best practice
. The definition of a pattern is
A solution to a problem in a context
This means that what is a good solution in one case won't be a good solution in another.
Application architecture 0 - Component composition
That's almost the "default" way of working with Blazor. Use multiple pages which contain components. Data goes down, changes go up, trying to go sideways is essentially impossible so developers have to follow the flow.
If a page or component gets too big, it's easy to extract it into a separate component with its own Parameter
s.
In some cases, component composition will be enough, especially when there's not a lot of complex state to manage or there aren't that many dependencies between components. Those components could call their own server-side APIs without increasing complexity. Different people could easily work on their own components independently up to a point.
Many quick projects start this way before becoming large enough to require a more complex architecture. When that happens, using components makes it far easier to adopt another architecture.
In eg an ERP or CRM application though, there's a lot of complex data to manage for even a single Customer. The same page may display multiple tabs coming from multiple systems, in summary or detail views. A single change may affect the display of multiple components on the same page.
Never mind that such applications often need to combine UI elements from different applications, and still behave as a single application. 15 years ago these were called Composite Applications
or Mashups
. Nowadays people talk about Micro-Frontends
Application architecture 1- MVVM
This pattern is used a lot in SPAs and WPF. In this design a separate ViewModel
is used for every View
with the actual state stored in a Model
. The Model
could be hiding a database or service calls. Multiple components that implement their own View/ViewModel
s can work with the same Model
, eg displaying current user data in different ways on every page.
There are a lot of articles on MVVM. I copied the image from MVVM Pattern in Blazor For State Management – A Complete Guide.

Communication between View and ViewModel uses Blazor data-binding. The ViewModel
class itself needs to implement INotifyPropertyChanged
, the same way it does in WPF, so changes to its properties can trigger View updates.
Application Architecture - MVU
This pattern originated in the Elm language, so it's also called the Elm Architecture
. It's rising in popularity and .NET MAUI works on a variant of MVU. This article describes how it works in F#.
The high-level image shows its major feature - flow is one-way only. The Update
part generates changes that are used to update the Model
. Sounds a lot like Redux, doesn't it?

The following image comes from Comet, an MVU pattern for .NET MAUI and makes it clearer how the concepts map to Blazor concepts like data binding:

In this case that component Parameter
s offer one-way binding but EventCallback
s need to generate updates for the Model
instead of notifying the parent component.
In Redux
, both Command
s and Update
s are top-level concepts, defined in advance, similar to messages, so the application state and components can be changed independent of each other.
Separating Code from Markup
The Partial class support section in the Blazor Component Overview page shows you can put the C# code in a code-behind file containing a partial class whose name is the same as your component. During compilation the code from all partial classes is merged into a single one and compiled as a single class.
Borrowing from the docs, if you have a component named Pages/Counter.razor
:
page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
You can split it into a .razor
and a .cs
file:
CounterPartialClass.razor
@page "/counter-partial-class"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
CounterPartialClass.razor.cs
namespace BlazorSample.Pages
{
public partial class CounterPartialClass
{
private int currentCount = 0;
void IncrementCount()
{
currentCount++;
}
}
}