Cuando Blazor apareció en 2019, la propuesta era clara: escribir la UI de tu aplicación web en C# sin tocar JavaScript. Mucha gente lo recibió con escepticismo. Siete años después, con .NET 8 y 9 ya encima de la mesa, la historia es bastante diferente. Blazor tiene cuatro modos de renderizado, soporte para PWA, interoperabilidad con JS cuando hace falta, y un modelo de componentes que se parece mucho a lo que ya conoces si vienes de React o Vue, pero en C#.
Esta guía va al grano: cómo funcionan los modos de renderizado, cómo se escribe un componente, cómo gestionar estado, cómo hacer interop con JavaScript y cuándo tiene sentido usar Blazor en lugar de un framework JS en 2026.
Los modos de renderizado: de dónde viene Blazor y dónde está ahora
Para entender el modelo actual tienes que conocer cómo fue evolucionando el framework.
Blazor Server (2019)
La primera versión disponible en producción. Con Blazor Server los componentes se ejecutan en el servidor: cuando el usuario interactúa con la página, el navegador envía el evento por SignalR, el servidor recalcula el DOM y envía solo el diff de vuelta. El cliente no descarga el runtime de .NET, lo que hace que la carga inicial sea rápida. La contrapartida es que necesitas conexión activa con el servidor todo el rato y la latencia de red afecta directamente a la respuesta de la UI.
Blazor WebAssembly (2020)
Con Blazor WASM el runtime de .NET se descarga al navegador y los componentes se ejecutan directamente ahí. No necesitas servidor para la lógica de UI, puedes servir la app como archivos estáticos y funcionar offline. El problema conocido es la descarga inicial, que incluye el runtime de .NET y puede pesar varios megabytes la primera vez.
Blazor United y el modo Auto (desde .NET 8)
Con .NET 8 Microsoft fusionó los dos modelos en lo que llamó Blazor United. La novedad más importante es que ya no tienes que elegir un modo para toda la aplicación: cada componente puede tener su propio modo de renderizado. Esto abre opciones que antes no existían, como arrancar en Server para que la primera respuesta sea rápida y migrar a WebAssembly en cuanto el runtime termine de descargarse en segundo plano.
Render modes en .NET 8 y 9: los cuatro que necesitas conocer
En .NET 8 se formalizaron cuatro modos de renderizado que puedes aplicar con el atributo @rendermode:
- InteractiveServer: renderizado en servidor con SignalR. Es el Blazor Server de siempre, pero ahora aplicable componente a componente.
- InteractiveWebAssembly: el componente se ejecuta en el navegador. Necesita que el runtime de .NET se haya descargado.
- InteractiveAuto: arranca en Server para respuesta inmediata y cambia automáticamente a WebAssembly cuando el runtime ya está disponible en el cliente. En sesiones posteriores usa WASM desde el principio.
- Static: renderizado estático en el servidor sin interactividad. Útil para páginas que no necesitan eventos del usuario, genera HTML puro.
Puedes aplicar el modo en el propio componente o al usarlo:
@* En la declaración del componente *@
@rendermode InteractiveAuto
@* O al instanciarlo desde otro componente *@
<MiComponente @rendermode="InteractiveServer" />
Además de estos cuatro, .NET 8 introdujo Static Server Rendering con Streaming: la página se prerenderiza en el servidor, se envía el HTML al cliente cuanto antes y después se activa la interactividad. Útil cuando quieres tiempo hasta primer byte bajo pero también necesitas componentes interactivos.
Anatomía de un componente Blazor
Los componentes de Blazor son archivos .razor que mezclan HTML con C# en el mismo archivo. La estructura básica tiene tres partes: las directivas arriba, el HTML en el medio y el bloque @code { } abajo con la lógica.
@page "/saludo"
<h1>Hola, @nombre</h1>
<button @onclick="Saludar">Saludar</button>
@code {
private string nombre = "mundo";
private void Saludar()
{
nombre = "Blazor";
}
}
Si el componente recibe datos de su padre, se declaran con [Parameter]:
@code {
[Parameter]
public string Titulo { get; set; } = "";
[Parameter]
public EventCallback<string> OnCambio { get; set; }
}
EventCallback<T> es el mecanismo para que un componente hijo notifique al padre de que algo ha cambiado. La inyección de dependencias funciona con @inject directamente en el componente:
@inject IProductoService productos
@inject NavigationManager nav
Gestión de estado: de lo simple a lo complejo
Para estado local al componente basta con variables en el bloque @code. Blazor se encarga de volver a renderizar el componente cuando cambia el estado dentro de un handler de evento. Si el cambio ocurre fuera del ciclo normal (por ejemplo, en un callback de un timer o un evento externo), necesitas llamar a StateHasChanged() para forzar el re-render:
private async Task CargarDatos()
{
datos = await api.ObtenerDatosAsync();
StateHasChanged(); // necesario si esto viene de fuera del ciclo de Blazor
}
Para estado compartido entre varios componentes en Blazor Server, lo habitual es crear un servicio registrado como Scoped. En Server, Scoped equivale a la sesión del usuario, así que funciona como un singleton por conexión. Inyectas el servicio en los componentes que lo necesitan y ya está.
En Blazor WebAssembly la cosa es distinta porque no hay servidor. Para estado persistente entre recargas puedes usar ProtectedLocalStorage (cifra los datos antes de guardarlos en localStorage) o tirar de una librería de gestión de estado como Fluxor, que implementa el patrón Flux para Blazor.
Interop con JavaScript: cuándo y cómo
Blazor no te obliga a prescindir de JavaScript. Cuando necesitas acceder a APIs del navegador que aún no tienen wrapper en .NET, o integrar una librería JS de terceros, usas IJSRuntime:
@inject IJSRuntime js
private async Task EjemploInterop()
{
// Llamar a una función JS sin retorno
await js.InvokeVoidAsync("console.log", "hola desde C#");
// Llamar a una función JS que devuelve un valor
string valor = await js.InvokeAsync<string>("miLibreria.obtenerValor");
}
También funciona al revés: puedes exponer métodos de C# para que JavaScript los llame con [JSInvokable]:
[JSInvokable]
public static string DesdeCSharp()
{
return "respuesta desde .NET";
}
// En JavaScript:
// await DotNet.invokeMethodAsync('MiApp', 'DesdeCSharp');
Una diferencia importante: en Blazor Server el interop es siempre asíncrono porque implica una ida y vuelta por la red (de servidor a navegador). En WebAssembly, como el código corre directamente en el navegador, también puedes usar InvokeVoid síncrono en algunos casos, aunque la versión async funciona en ambos y es preferible para mantener código compatible.
Formularios con EditForm y validación
Blazor tiene su propio sistema de formularios centrado en EditForm. El flujo básico es este: defines un modelo, lo enlazas al formulario y usas los componentes de input de Blazor para el binding bidireccional:
<EditForm Model="@miModelo" OnValidSubmit="@Guardar">
<DataAnnotationsValidator />
<ValidationSummary />
<InputText @bind-Value="miModelo.Nombre" />
<InputNumber @bind-Value="miModelo.Edad" />
<button type="submit">Guardar</button>
</EditForm>
DataAnnotationsValidator recoge las validaciones que hayas definido en el modelo con atributos como [Required], [StringLength] o [Range]. ValidationSummary muestra los errores. OnValidSubmit solo se ejecuta si la validación pasa; si no, el formulario muestra los errores sin llamar a tu método.
Para validaciones más complejas, FluentValidation tiene integración con Blazor y te permite definir las reglas en clases separadas con una sintaxis más expresiva que los Data Annotations.
Blazor vs React y Vue en 2026: una comparativa sin rodeos
La pregunta que se hacen los equipos cuando evalúan Blazor no es técnica sino de contexto. Aquí tienes los factores que de verdad pesan:
A favor de Blazor: si tu equipo es de backend .NET y no quiere mantener dos lenguajes, Blazor elimina esa fricción. Puedes compartir modelos, validaciones y lógica de negocio entre frontend y backend sin duplicar código. Para aplicaciones internas de empresa, portales de gestión o backoffices con equipos pequeños y stack Microsoft, es una opción muy sólida.
A favor de React y Vue: el catálogo de componentes de UI para React sigue siendo mucho más amplio. Si necesitas tablas de datos avanzadas, editores de texto enriquecido o visualizaciones complejas, React tiene más opciones maduras. Además, la mayor parte de los desarrolladores frontend del mercado trabajan con JS, así que contratar resulta más fácil. Para aplicaciones públicas con equipos especializados en frontend, React y Vue siguen siendo la opción más pragmática.
La línea divisoria en 2026 está bastante clara: ASP.NET Core y el desarrollo web con C# ya tienen un lugar consolidado en el mercado empresarial, y C# en el frontend: la propuesta de Blazor tiene sentido cuando el equipo ya vive en ese mundo. Para proyectos nuevos con equipo mixto o sin historial en .NET, la barrera de entrada de React sigue siendo menor.
PWA con Blazor WASM: aplicaciones offline
Blazor WebAssembly tiene soporte para Progressive Web Apps desde hace tiempo. Crear una PWA es tan sencillo como:
dotnet new blazorwasm --pwa -o MiPwa
Eso genera una plantilla con Service Worker incluido que cachea los archivos de la aplicación para que funcione sin conexión. El manifiesto de la app está en wwwroot/manifest.json y ahí defines el nombre, los iconos y cómo se comporta cuando el usuario la instala en el escritorio o en el móvil.
El punto débil sigue siendo el mismo que en 2020: la descarga inicial del runtime de .NET pesa varios megabytes. En redes lentas eso se nota. Con .NET 9 el tamaño ha bajado algo gracias al trimming mejorado, pero sigue siendo una consideración real si tu audiencia tiene conexiones lentas o dispositivos de gama baja. Para esos casos, el modo InteractiveAuto puede ser mejor opción porque arranca en Server mientras el runtime se descarga en segundo plano.
Por dónde empezar si vienes de otro stack
Si ya sabes C# y quieres probar Blazor, el punto de entrada más cómodo en 2026 es una plantilla de Blazor Web App (que usa el modelo unificado de .NET 8):
dotnet new blazor -o MiApp
cd MiApp
dotnet run
Eso te da una app con los cuatro modos de renderizado disponibles desde el primer momento. Puedes ir probando @rendermode en distintos componentes y ver cómo cambia el comportamiento sin tocar nada más de la configuración.
La documentación oficial en learn.microsoft.com/aspnet/core/blazor/ está bastante bien organizada y cubre los render modes con ejemplos. Para los detalles más finos del modo Auto y las diferencias de comportamiento entre Server y WASM, la sección de "ASP.NET Core Blazor render modes" es la referencia.
Imagen: Pexels / William Warby
