Times .NET têm hoje uma escolha genuína de frontend: usar React (ou Next.js) como sempre foi feito, ou usar Blazor e escrever o frontend inteiro em C#. A pergunta não é qual é tecnicamente "melhor" — é qual faz sentido para o seu contexto. Este guia cobre os trade-offs reais que aparecem em produção.
Blazor em duas versões: Server e WebAssembly
Blazor não é uma tecnologia única — são dois modelos de execução com características muito diferentes:
Blazor Server: O C# roda no servidor. O browser recebe HTML renderizado e uma conexão SignalR permanente. Eventos de UI (cliques, inputs) são enviados ao servidor, o C# processa e manda diff do DOM de volta. Resultado: bundle mínimo no browser, acesso direto ao banco e serviços, mas latência em cada interação e sem funcionamento offline.
Blazor WebAssembly (WASM): O runtime .NET roda no browser via WebAssembly. O C# executa client-side, sem conexão permanente com o servidor. Download inicial pesado (~5-10MB), mas funciona offline e tem latência de UI como qualquer SPA. Ideal para aplicações que não podem depender de conexão constante.
Blazor Server na prática
// Componente Blazor Server — código idêntico para UI e lógica
@page "/pedidos"
@using PedidosApp.Services
@inject IPedidoService PedidoService
<h1>Pedidos</h1>
@if (_carregando)
{
<p>Carregando...</p>
}
else if (_pedidos is null || !_pedidos.Any())
{
<p>Nenhum pedido encontrado.</p>
}
else
{
<table>
<thead>
<tr><th>ID</th><th>Cliente</th><th>Status</th></tr>
</thead>
<tbody>
@foreach (var pedido in _pedidos)
{
<tr>
<td>@pedido.Id</td>
<td>@pedido.Cliente</td>
<td>@pedido.Status</td>
</tr>
}
</tbody>
</table>
}
@code {
private List<PedidoDto>? _pedidos;
private bool _carregando = true;
protected override async Task OnInitializedAsync()
{
// Acesso direto ao serviço C# — sem API intermediária
_pedidos = await PedidoService.ListarAsync();
_carregando = false;
}
}
O poder aqui é o que não existe: sem API, sem serialização/deserialização, sem estado gerenciado no cliente, sem tipos duplicados (um para o backend, um para o frontend). O desenvolvedor C# escreve o front sem aprender um framework JavaScript.
React no ecossistema .NET
// React com TypeScript consumindo a mesma API .NET
// Tipos precisam ser re-declarados (ou gerados via NSwag/Kiota)
interface PedidoDto {
id: number;
cliente: string;
status: string;
}
function PedidosList() {
const [pedidos, setPedidos] = useState<PedidoDto[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/pedidos')
.then(r => r.json())
.then(data => {
setPedidos(data);
setLoading(false);
});
}, []);
if (loading) return <p>Carregando...</p>;
if (!pedidos.length) return <p>Nenhum pedido.</p>;
return (
<table>
<thead><tr><th>ID</th><th>Cliente</th><th>Status</th></tr></thead>
<tbody>
{pedidos.map(p => (
<tr key={p.id}>
<td>{p.id}</td>
<td>{p.cliente}</td>
<td>{p.status}</td>
</tr>
))}
</tbody>
</table>
);
}
Comparativo por critério
Performance de UI: React tem vantagem em interações rápidas e animações complexas. Blazor Server adiciona latência de rede em cada evento (um clique gera round-trip ao servidor). Blazor WASM é comparável ao React, mas startup é mais lento. Para dashboards analíticos com pouca interação, a diferença é irrelevante. Para formulários com validação em tempo real ou grids editáveis grandes, React é mais responsivo.
SEO: React com Next.js (SSR/SSG) tem SEO excelente. Blazor Server renderiza HTML no servidor — SEO nativo sem configuração adicional. Blazor WASM puro não tem SEO (igual a React SPA puro), mas existe o modo de pre-rendering híbrido. Para sites de conteúdo ou marketing, Next.js ou Blazor Server são as escolhas SEO-friendly.
Tamanho de bundle e primeira carga: Blazor WASM faz download do runtime .NET (~6MB gzipped) na primeira visita. React + bibliotecas típicas: ~200-500KB. Blazor Server: mínimo no cliente, mas exige conexão constante. Para aplicações internas (intranet, backoffice) onde o cache resolve o download inicial, Blazor WASM é aceitável. Para apps públicos, o peso do WASM é real.
Produtividade do time: Este é o critério mais subestimado. Um time .NET sem experiência em JavaScript leva semanas para ganhar produtividade com React (TypeScript, bundlers, state management, async patterns do JavaScript). Com Blazor, o mesmo time escreve frontend no dia seguinte. Para squads small onde não existe frontend especializado, Blazor pode triplicar a velocidade de entrega.
Ecossistema de componentes: React tem o maior ecossistema de componentes UI do mundo: MUI, shadcn/ui, Radix, AG Grid, Recharts, etc. Blazor tem MudBlazor, Radzen, Syncfusion — bons, mas menores. Para UIs muito customizadas com muitos componentes de terceiros, React tem vantagem. Para aplicações padrão CRUD, ambos têm o que você precisa.
Quando escolher Blazor Server
Blazor Server é a melhor escolha quando: o time é 100% .NET e JavaScript é uma barreira real de produtividade, é um sistema interno (ERP, backoffice, gestão) onde latência de rede é aceitável (conexão LAN/VPN), você quer acesso direto a serviços .NET sem API intermediária, ou precisa de autenticação integrada com ASP.NET Core Identity sem duplicar a lógica.
// Blazor Server com autenticação direta — sem JWT, sem cookies customizados
// O usuário já autenticado no ASP.NET Core está disponível no componente
@page "/admin"
@attribute [Authorize(Roles = "Admin")]
@inject AuthenticationStateProvider AuthState
@code {
private string? _nomeUsuario;
protected override async Task OnInitializedAsync()
{
var authState = await AuthState.GetAuthenticationStateAsync();
_nomeUsuario = authState.User.Identity?.Name;
}
}
Quando escolher Blazor WASM
Blazor WASM faz sentido quando: o app precisa funcionar offline ou com conexão instável (PWA), quer isolar completamente frontend de backend (deploy em CDN), o time .NET precisa escrever um app "desktop-like" no browser sem aprender JS, ou você quer compartilhar modelos e validações entre frontend e backend no mesmo projeto (bibliotecas de classes compartilhadas).
// Compartilhamento de código entre WASM e API — único projeto de contratos
// PedidosApp.Shared (biblioteca de classes)
public class CriarPedidoRequest
{
[Required(ErrorMessage = "ClienteId é obrigatório")]
public int ClienteId { get; set; }
[MinLength(1, ErrorMessage = "Mínimo 1 item")]
public List<PedidoItem> Itens { get; set; } = new();
}
// Mesmo modelo usado no componente Blazor WASM e no controller .NET
// Zero duplicação de validação, zero divergência de tipos
Quando escolher React
React (ou Next.js) é a escolha mais segura quando: o produto é público e SEO e performance de loading importam, a UI é complexa com muitas animações, drag-and-drop ou interações sofisticadas, você precisa de um ecossistema de componentes maduro e extenso, o time já tem frontend developers com experiência JS/TS, ou o projeto pode crescer para incluir um app mobile (React Native) — compartilhando lógica.
A opção híbrida: Blazor para admin, React/Next.js para público
Muitas arquiteturas usam os dois: Next.js para o site público e landing pages (SEO, performance, rich UI), e Blazor Server para o painel administrativo interno (produtividade do time .NET, acesso direto ao banco, menos concerns de SEO). O backend é o mesmo — uma ASP.NET Core API que serve ambos.
A decisão entre Blazor e React não é ideológica. É pragmática: quem vai manter o código, qual é o contexto de uso, e quais trade-offs você pode aceitar. Times full-.NET que adotam Blazor para backoffice interno costumam relatar ganhos de produtividade de 30-50% versus montar um frontend React separado. Times com frontend especializado raramente sentem falta do Blazor — o ecossistema React já resolve tudo o que precisam.