# Support Prerendering

Make interactive Blazor components work correctly with prerendering.

- Repository: https://github.com/dotnet/skills (5787 stars)
- Category: Design
- License: MIT
- Last updated: 2026-11-01
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add dotnet/skills --skill support-prerendering -g -a claude-code -y`
Codex: `npx skills add dotnet/skills --skill support-prerendering -g -a codex -y`
Cursor: `npx skills add dotnet/skills --skill support-prerendering -g -a cursor -y`
Gemini CLI: `npx skills add dotnet/skills --skill support-prerendering -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add dotnet/skills`

## Description

Make interactive Blazor components work correctly with prerendering. USE FOR fixing duplicate data loads, UI flicker during prerender-to-interactive handoff, null references during prerender, persisting state across prerender, disabling prerendering, excluding pages from interactive routing, or detecting whether a component is currently prerendering. DO NOT USE for choosing which render mode to use (see create-blazor-project) or general component authoring (see author-component).

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# Support Prerendering

## How Prerendering Works

Prerendering is **on by default** for all interactive render modes. The server renders the component as static HTML and ships it to the browser immediately. Then the interactive runtime (Server/WebAssembly) loads and re-renders the component with full interactivity.

This means:
- `OnInitializedAsync` runs **twice**, once during prerender (static), once when the interactive runtime attaches.
- `OnAfterRenderAsync` is **NOT** called during prerender, only after the interactive render.
- Internal navigation between interactive pages (interactive routing) **skips prerendering**, prerendering only happens on full page loads.

## Step 1, Read the Project's AGENTS.md

Check the project's `AGENTS.md` for the **Interactivity Mode** and **Interactivity Scope**:

| Mode | Prerendering applies? |
|------|----------------------|
| None (Static SSR) | No, there's no interactive handoff |
| Server | Yes |
| WebAssembly | Yes |
| Auto | Yes |

If the mode is `None`, this skill doesn't apply.

## Persist State Across Prerender → Interactive

The most common prerendering problem: data loaded in `OnInitializedAsync` during prerender is thrown away and re-fetched when the interactive runtime attaches. This causes flicker and duplicate API/DB calls.

### Recommended: `[PersistentState]` attribute

Annotate properties to automatically serialize during prerender and restore on interactive activation:

```razor
@page "/forecasts"
@rendermode InteractiveServer

<h1>Weather</h1>

@if (Forecasts is null)
{
    <p>Loading...</p>
}
else
{
    @foreach (var f in Forecasts)
    {
        <p>@f.Date: @f.TemperatureC°C</p>
    }
}

@code {
    [PersistentState]
    public WeatherForecast[]? Forecasts { get; set; }

    protected override async Task OnInitializedAsync()
    {
        Forecasts ??= await ForecastService.GetForecastsAsync();
    }
}
```

The rest: https://github.com/dotnet/skills/blob/HEAD/plugins/dotnet-blazor/skills/support-prerendering/SKILL.md
