
Create Blazor Project
- 1 installs
- 466 repo stars
- Updated July 25, 2026
- managedcode/dotnet-skills
Scaffolds a new Blazor Web App with dotnet new blazor, gathering requirements and choosing the right render mode from Static SSR through Interactive WebAssembly.
About
A skill for creating a new Blazor Web App and picking the simplest render mode that meets requirements. A developer uses it to scaffold a new web project and choose Static SSR, Interactive Server, WebAssembly, or Auto.
- Gathers app, interactivity, deployment, and auth requirements first
- Render modes as a progression starting at the simplest that fits
Create Blazor Project by the numbers
- 1 all-time installs (skills.sh)
- Ranked #121 of 153 .NET & C# skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/managedcode/dotnet-skills --skill create-blazor-projectAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 466 |
| Last updated | July 25, 2026 |
| Repository | managedcode/dotnet-skills ↗ |
What it does
Scaffolds a new Blazor Web App with dotnet new blazor, gathering requirements and choosing the right render mode from Static SSR through Interactive WebAssembly.
Files
Create a Blazor Web App
Before You Start — Gather Requirements
If the user's request doesn't make the following clear, ask before scaffolding:
1. What does the app do? List the main screens/features (e.g., "product catalog with search and shopping cart"). 2. What kind of interactivity is needed? Displaying data and forms? Real-time updates? Offline support? Rich drag-and-drop UI? 3. Deployment environment? Internet-facing? Intranet? Mobile users on slow connections? 4. Authentication needed? Anonymous? Individual accounts? Organizational (Azure AD)?
Pick the Right Interactivity Level
Blazor render modes are a progression scale. Start at the simplest level that satisfies the requirements and only move up when there's a concrete reason.
Static SSR ──→ SSR + Enhanced Nav ──→ Interactive Server ──→ Interactive WebAssembly
simplest most complexDecision Rules
| If the app needs... | Use | Why |
|---|---|---|
| Display data, simple forms, links between pages | Static SSR (-int None) | No JS runtime, no circuit, no WebAssembly download. Forms work via HTML POST. Enhanced navigation makes it feel snappy. |
| Everything above + a few components with client-side behavior (live search, real-time updates, complex form wizards) | Interactive Server, per-page (-int Server) | Only the components that need interactivity opt in with @rendermode. The rest stays static. Server-side execution, full .NET access, no API layer needed. |
| Most pages need rich interactivity (dashboards, drag-and-drop, chat) | Interactive Server, global (-int Server -ai) | Every component is interactive by default. Consistent UX, simpler mental model. Trade-off: every user holds a SignalR circuit on the server. |
| Network latency is a problem, users are on mobile/poor connections, or the app must work offline | Interactive WebAssembly (-int WebAssembly) | Code runs in the browser. Eliminates round-trip latency but requires a .Client project, API layer for data access, and downloads the .NET runtime to the browser on first visit. For offline support, enable PWA: add a service worker and manifest after scaffolding (not included in the template by default). |
| Fast initial load (Server) + low latency after (WebAssembly) | Interactive Auto (-int Auto) | First visit uses Server; subsequent visits use cached WebAssembly runtime. Most complex setup — see Auto constraints below. Only choose when both Server and WebAssembly constraints apply. |
Default recommendation: Start with -int Server (per-page). It covers the vast majority of apps. Upgrade to global or WebAssembly only when a specific requirement demands it.
Auto Mode Constraints
Auto mode means your component code runs on the server first, then in the browser on subsequent visits. This creates real constraints:
- All interactive components must live in the `.Client` project — same as WebAssembly.
- No direct server access from interactive components — no EF
DbContext, no file system, no server-only services. All data access must go through HTTP APIs. - Both `Program.cs` files must register matching services — the server and client DI containers must both provide implementations for any service an interactive component injects.
- Code must not assume its execution environment — no
HttpContextaccess, no browser-only APIs withoutRendererInfoguards. - Test in both modes — a component that works on Server during development may break on WebAssembly in production (second visit). Test both paths.
Don'ts
- Don't pick WebAssembly "because it's cool" — it adds a
.Clientproject, forces API-mediated data access, and downloads ~10MB to the browser on first visit. - Don't pick Auto unless you can articulate why Server alone and WebAssembly alone are both insufficient.
- Don't pick global interactivity for apps where most pages are read-only content — per-page keeps the static pages fast and reduces server memory.
Scaffold the Project
Static SSR Only (display data + simple forms)
dotnet new blazor -o {AppName} -int NoneNo interactive runtime. Enhanced navigation enabled by default via blazor.web.js.
Interactive Server, Per-Page (recommended default)
dotnet new blazor -o {AppName} -int ServerPages are static by default. Add @rendermode InteractiveServer to components that need interactivity.
Interactive Server, Global
dotnet new blazor -o {AppName} -int Server -aiAll pages interactive via <Routes @rendermode="InteractiveServer" /> in App.razor.
Interactive WebAssembly, Per-Page
dotnet new blazor -o {AppName} -int WebAssemblyCreates {AppName} (server) and {AppName}.Client (WebAssembly) projects. Interactive components must live in .Client.
Interactive WebAssembly, Global
dotnet new blazor -o {AppName} -int WebAssembly -aiInteractive Auto, Per-Page
dotnet new blazor -o {AppName} -int AutoInteractive Auto, Global
dotnet new blazor -o {AppName} -int Auto -aiWith Authentication
Append -au Individual to any command above:
dotnet new blazor -o {AppName} -int Server -au Individual-au Individual scaffolds ASP.NET Core Identity with SQLite (CLI) or SQL Server (Visual Studio). Identity pages are always static SSR — they do not use interactive render modes.
The blazor template only supports -au Individual. For organizational auth (Microsoft Entra ID, Azure AD B2C), scaffold with -au Individual first, then replace the Identity provider with Microsoft.Identity.Web / OIDC middleware and configure the tenant in appsettings.json.
What the Template Creates
Single project (Static SSR, Server)
{AppName}/
├── Components/
│ ├── App.razor # Root component — sets <HeadOutlet> and <Routes>
│ ├── Routes.razor # Wraps <Router> with route discovery
│ ├── Layout/
│ │ ├── MainLayout.razor # App shell with nav, header, footer
│ │ └── MainLayout.razor.css
│ └── Pages/
│ └── Home.razor # @page "/" — first page
├── Program.cs # Service registration and middleware
├── wwwroot/ # Static files (CSS, images)
└── {AppName}.csprojTwo projects (WebAssembly, Auto)
{AppName}/ # Server project — hosts the app
├── Components/ # Server-only components (static SSR pages, layouts)
│ ├── App.razor
│ ├── Routes.razor
│ └── Layout/
├── Program.cs # Server Program.cs
└── {AppName}.Client/ # Client project — WebAssembly components
├── Pages/ # Interactive components go HERE
├── Program.cs # Client Program.cs
└── _Imports.razorRule: Components using InteractiveWebAssembly or InteractiveAuto must live in the .Client project. They can reference shared code but cannot reference server-only types (EF DbContext, server-side services).
Program.cs Wiring
The template generates the correct Program.cs for the chosen mode. Verify these registrations match your intent:
Static SSR Only
// Program.cs
builder.Services.AddRazorComponents();
// ...
app.MapRazorComponents<App>();Server (per-page or global)
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
// ...
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();WebAssembly (per-page or global)
// Server Program.cs
builder.Services.AddRazorComponents()
.AddInteractiveWebAssemblyComponents();
// ...
app.MapRazorComponents<App>()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof({AppName}.Client._Imports).Assembly);// Client Program.cs
builder.Services.AddAuthorizationCore();
// Register HttpClient, other client-side servicesCreate Project AGENTS.md
After scaffolding, create an AGENTS.md file in the project root (next to the .csproj). For two-project setups, put it in the server project root.
Pick the matching template from assets/agents-md/ based on the chosen mode:
| Mode | Template file |
|---|---|
Static SSR (-int None) | assets/agents-md/ssr-none.md |
Server, per-page (-int Server) | assets/agents-md/server-per-page.md |
Server, global (-int Server -ai) | assets/agents-md/server-global.md |
WebAssembly, per-page (-int WebAssembly) | assets/agents-md/webassembly-per-page.md |
WebAssembly, global (-int WebAssembly -ai) | assets/agents-md/webassembly-global.md |
Auto, per-page (-int Auto) | assets/agents-md/auto-per-page.md |
Auto, global (-int Auto -ai) | assets/agents-md/auto-global.md |
Copy the template contents into the project's AGENTS.md and replace every {AppName} with the actual project name. If auth was scaffolded (-au Individual), add an ## Authentication section noting that ASP.NET Core Identity is configured and that Identity pages under Components/Account/ are always static SSR — do not add @rendermode to them.
After scaffolding the project and creating AGENTS.md, continue implementing the features the user requested. Remove default template pages (Counter, Weather) and replace them with the actual application pages.
Auto (per-page or global)
// Server Program.cs
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddInteractiveWebAssemblyComponents();
// ...
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof({AppName}.Client._Imports).Assembly);App.razor — Global vs Per-Page
The difference between global and per-page interactivity is entirely in App.razor:
Per-page (default)
<!DOCTYPE html>
<html>
<head>
<HeadOutlet />
</head>
<body>
<Routes />
<script src="_framework/blazor.web.js"></script>
</body>
</html>No @rendermode on <Routes> or <HeadOutlet>. Individual pages opt in.
Global
<!DOCTYPE html>
<html>
<head>
<HeadOutlet @rendermode="InteractiveServer" />
</head>
<body>
<Routes @rendermode="InteractiveServer" />
<script src="_framework/blazor.web.js"></script>
</body>
</html>Replace InteractiveServer with InteractiveWebAssembly or InteractiveAuto as appropriate.
After Scaffolding
1. Verify it builds: dotnet build 2. Run it: dotnet run (in the server project if two-project setup) 3. Add your first page: Create a .razor file in Components/Pages/ (server project) or Pages/ (.Client project for WebAssembly components)
Don'ts
- Don't use
dotnet new blazorwasm— that creates a standalone WebAssembly SPA without server-side rendering. Use theblazortemplate with-int WebAssemblyinstead. - Don't manually add
AddInteractiveServerComponents()to a project created with-int Noneand expect it to work — you also need the@rendermodedirectives and potentiallyApp.razorchanges. Re-scaffold if the mode needs to change fundamentally. - Don't put WebAssembly-targeted components in the server project — they'll work during prerender but fail after handoff.
{AppName}
| Setting | Value |
|---|---|
| Interactivity Mode | Auto |
| Interactivity Scope | Global |
Rendering configuration
This project uses global Interactive Auto with prerendering. Created with dotnet new blazor -int Auto -ai.
On a user's first visit, components render via Interactive Server (SignalR). On subsequent visits the cached WebAssembly runtime takes over and interactions run entirely in the browser.
Project structure
- {AppName} (server): Hosts the Blazor app, serves static files, API endpoints.
- {AppName}.Client (WebAssembly): All interactive UI components. Run on server first, then browser.
Adding new components
- Interactive components MUST go in the
.Clientproject, not the server project. - New pages go in
{AppName}.Client/Pages/. - All pages are already interactive (global mode). No need to add
@rendermodeto individual components. - Server-only static components (e.g., error pages) belong in the server
Components/folder.
Data access
Interactive components cannot access the database directly. Use this pattern: 1. Define an interface in the .Client project (e.g., IDataService). 2. In the .Client project, implement it using HttpClient to call server APIs. 3. In the server project, implement it using direct data access (EF Core DbContext, etc.). 4. Register the client implementation in the client Program.cs and the server implementation in the server Program.cs. 5. Expose server data through minimal API endpoints (e.g., app.MapGet(...)) that the client implementation calls. 6. If the page requires authorization, apply the same auth policy to both the Blazor page (@attribute [Authorize]) and the minimal API endpoint (.RequireAuthorization()).
Service registration
- Both server and client
Program.csmust register matching services for any DI used by interactive components. - Server-only services (EF Core, Identity) stay in the server
Program.csonly.
Environment constraints
- Code must work in both server and browser execution environments.
- Do not use
HttpContextor browser-only JS APIs withoutRendererInfoguards. - The .NET runtime (~10 MB) is downloaded to the browser on first visit and cached — subsequent visits use WebAssembly.
Don'ts
- Don't put interactive components in the server project — they work during prerender but fail after WebAssembly handoff.
- Don't inject
DbContextor server-only services in.Clientproject components — use HTTP APIs instead. - Don't assume execution environment — the same component runs on Server first, then WebAssembly later. Test both.
- Don't add
@rendermode InteractiveAutoto pages — global interactivity is already configured inApp.razor. - Don't add
@rendermodeto Identity/Account pages if auth is configured — they must stay static SSR.
{AppName}
| Setting | Value |
|---|---|
| Interactivity Mode | Auto |
| Interactivity Scope | Per-page |
Rendering configuration
This project uses per-page Interactive Auto with prerendering. Created with dotnet new blazor -int Auto.
Pages are static SSR by default. Components that add @rendermode InteractiveAuto use Server on first visit, then WebAssembly on subsequent visits once the runtime is cached.
Project structure
- {AppName} (server): Hosts the Blazor app, serves static files, API endpoints. Static SSR pages and layouts live here.
- {AppName}.Client (WebAssembly): Interactive components that run on server first, then browser.
Adding new components
- Interactive components MUST go in the
.Clientproject, not the server project. - New pages in the server
Components/Pages/are static SSR by default. - Only add
@rendermode InteractiveAutoto components that need client-side interactivity. - Static pages can use standard HTML forms with
[SupplyParameterFromForm]— no interactivity needed.
Data access
Interactive components cannot access the database directly. Use this pattern: 1. Define an interface in the .Client project (e.g., IDataService). 2. In the .Client project, implement it using HttpClient to call server APIs. 3. In the server project, implement it using direct data access (EF Core DbContext, etc.). 4. Register the client implementation in the client Program.cs and the server implementation in the server Program.cs. 5. Expose server data through minimal API endpoints (e.g., app.MapGet(...)) that the client implementation calls. 6. If the page requires authorization, apply the same auth policy to both the Blazor page (@attribute [Authorize]) and the minimal API endpoint (.RequireAuthorization()).
Service registration
- Both server and client
Program.csmust register matching services for any DI used by interactive components. - Server-only services (EF Core, Identity) stay in the server
Program.csonly.
Environment constraints
- Code must work in both server and browser execution environments.
- Do not use
HttpContextor browser-only JS APIs withoutRendererInfoguards. - The .NET runtime (~10 MB) is downloaded to the browser on first visit and cached — subsequent visits use WebAssembly.
- Static SSR pages in the server project have full server access.
Don'ts
- Don't put interactive components in the server project — they work during prerender but fail after WebAssembly handoff.
- Don't inject
DbContextor server-only services in.Clientproject components — use HTTP APIs instead. - Don't assume execution environment — the same component runs on Server first, then WebAssembly later. Test both.
- Don't set
@rendermodeon<Routes>inApp.razor— that makes it global. Per-page mode means individual components opt in. - Don't add
@rendermodeto Identity/Account pages if auth is configured — they must stay static SSR.
{AppName}
| Setting | Value |
|---|---|
| Interactivity Mode | Server |
| Interactivity Scope | Global |
Rendering configuration
This project uses global Interactive Server with prerendering. Created with dotnet new blazor -int Server -ai.
All pages are interactive by default via <Routes @rendermode="InteractiveServer" /> in App.razor.
Adding new components
- Create new
.razorfiles inComponents/Pages/for routable pages orComponents/for shared components. - All pages are already interactive. No need to add
@rendermodeto individual components.
Data access
- Components can inject services directly — EF Core DbContext, file system, server-only APIs. No HTTP API layer needed.
Environment constraints
- Components run on the server via SignalR.
HttpContextis NOT available in interactive components — it's only available during the initial static prerender.- Browser APIs are not directly available — use
IJSRuntimeinterop. - Every connected user holds a SignalR circuit on the server.
Don'ts
- Don't add
@rendermode InteractiveServerto pages — global interactivity is already configured inApp.razor. - Don't add
@rendermodeto Identity/Account pages if auth is configured — they must stay static SSR. - Don't inject
HttpContextin interactive components — it's not available during SignalR circuit lifetime. - Don't use browser APIs (localStorage, DOM) directly — use
IJSRuntimeinterop instead.
{AppName}
| Setting | Value |
|---|---|
| Interactivity Mode | Server |
| Interactivity Scope | Per-page |
Rendering configuration
This project uses per-page Interactive Server with prerendering. Created with dotnet new blazor -int Server.
Pages are static SSR by default. Only components that explicitly add @rendermode InteractiveServer become interactive.
Adding new components
- Create new
.razorfiles inComponents/Pages/for routable pages orComponents/for shared components. - New pages are static SSR by default. Only add
@rendermode InteractiveServerto components that need client-side behavior (live search, real-time updates, complex form interactions). - Static pages can use standard HTML forms with
[SupplyParameterFromForm]— no interactivity needed.
Data access
- Components can inject services directly — EF Core DbContext, file system, server-only APIs. No HTTP API layer needed.
Environment constraints
- Interactive components run on the server via SignalR.
HttpContextis available in static components but NOT in interactive components during the SignalR circuit lifetime. - Static pages can access
HttpContextvia[CascadingParameter]. - Browser APIs are not directly available — use
IJSRuntimeinterop in interactive components.
Don'ts
- Don't add
@rendermode InteractiveServerto every page — keep read-only content static for performance and lower server memory. - Don't add
@rendermodeto Identity/Account pages if auth is configured — they must stay static SSR. - Don't inject
HttpContextin interactive components — it's not available during SignalR circuit lifetime. - Don't set
@rendermodeon<Routes>inApp.razor— that makes it global. Per-page mode means individual components opt in.
{AppName}
| Setting | Value |
|---|---|
| Interactivity Mode | None (Static SSR) |
| Interactivity Scope | N/A |
Rendering configuration
This project uses static server-side rendering with no interactivity. Created with dotnet new blazor -int None.
Enhanced navigation via blazor.web.js is enabled by default, making page transitions feel instant without any interactive runtime.
Adding new components
- Create new
.razorfiles inComponents/Pages/for routable pages orComponents/for shared components. - Do NOT add
@rendermodeto any component — this project has no interactive runtime configured. - Forms use standard HTML POST with
[SupplyParameterFromForm]for model binding. - Query string parameters use
[SupplyParameterFromQuery].
Data access
- Components can inject services directly — EF Core DbContext, file system, server-only APIs. No HTTP API layer needed.
Environment constraints
- No SignalR circuits, no WebAssembly. All rendering happens on the server.
- Forms use HTML POST with
[SupplyParameterFromForm]and require<AntiforgeryToken />. HttpContextis available via[CascadingParameter].- Browser APIs (JS interop) are not available.
Don'ts
- Don't add
@rendermode InteractiveServeror any interactive render mode — the project has no interactive runtime registered. - Don't add
AddInteractiveServerComponents()toProgram.cswithout also updatingApp.razor. - Don't use
@onclickor other event handlers — they require an interactive render mode. Use form submissions and links for user actions. - Don't use
IJSRuntime— there is no interactive runtime to execute JavaScript calls.
{AppName}
| Setting | Value |
|---|---|
| Interactivity Mode | WebAssembly |
| Interactivity Scope | Global |
Rendering configuration
This project uses global Interactive WebAssembly with prerendering. Created with dotnet new blazor -int WebAssembly -ai.
All pages are interactive by default via <Routes @rendermode="InteractiveWebAssembly" /> in App.razor. Components run entirely in the browser after the initial prerender.
Project structure
- {AppName} (server): Hosts the Blazor app, serves static files, API endpoints.
- {AppName}.Client (WebAssembly): All interactive UI components. Runs entirely in the browser.
Adding new components
- All interactive components MUST go in the
.Clientproject, not the server project. - New pages go in
{AppName}.Client/Pages/. - All pages are already interactive. No need to add
@rendermodeto individual components.
Data access
Interactive components cannot access the database directly. Use this pattern: 1. Define an interface in the .Client project (e.g., IDataService). 2. In the .Client project, implement it using HttpClient to call server APIs. 3. In the server project, implement it using direct data access (EF Core DbContext, etc.). 4. Register the client implementation in the client Program.cs and the server implementation in the server Program.cs. 5. Expose server data through minimal API endpoints (e.g., app.MapGet(...)) that the client implementation calls. 6. If the page requires authorization, apply the same auth policy to both the Blazor page (@attribute [Authorize]) and the minimal API endpoint (.RequireAuthorization()).
Service registration
- Client-side services go in
{AppName}.Client/Program.cs. - Server-side services go in
{AppName}/Program.cs.
Environment constraints
- Components run in the browser via WebAssembly. No
HttpContext, no server file system. - All data access goes through
HttpClientcalls to server API endpoints. - The .NET runtime (~10 MB) is downloaded to the browser on first visit and cached.
Don'ts
- Don't put interactive components in the server project — they work during prerender but fail after WebAssembly handoff.
- Don't inject
DbContextor server-only services in.Clientproject components — use HTTP APIs instead. - Don't add
@rendermode InteractiveWebAssemblyto pages — global interactivity is already configured inApp.razor. - Don't add
@rendermodeto Identity/Account pages if auth is configured — they must stay static SSR.
{AppName}
| Setting | Value |
|---|---|
| Interactivity Mode | WebAssembly |
| Interactivity Scope | Per-page |
Rendering configuration
This project uses per-page Interactive WebAssembly with prerendering. Created with dotnet new blazor -int WebAssembly.
Pages are static SSR by default. Only components that explicitly add @rendermode InteractiveWebAssembly become interactive and run in the browser.
Project structure
- {AppName} (server): Hosts the Blazor app, serves static files, API endpoints. Static SSR pages and layouts live here.
- {AppName}.Client (WebAssembly): Interactive components that run in the browser.
Adding new components
- Interactive components MUST go in the
.Clientproject, not the server project. - New pages in the server
Components/Pages/are static SSR by default. - Only add
@rendermode InteractiveWebAssemblyto components that need client-side interactivity. - Static pages can use standard HTML forms with
[SupplyParameterFromForm]— no interactivity needed.
Data access
Interactive components cannot access the database directly. Use this pattern: 1. Define an interface in the .Client project (e.g., IDataService). 2. In the .Client project, implement it using HttpClient to call server APIs. 3. In the server project, implement it using direct data access (EF Core DbContext, etc.). 4. Register the client implementation in the client Program.cs and the server implementation in the server Program.cs. 5. Expose server data through minimal API endpoints (e.g., app.MapGet(...)) that the client implementation calls. 6. If the page requires authorization, apply the same auth policy to both the Blazor page (@attribute [Authorize]) and the minimal API endpoint (.RequireAuthorization()).
Service registration
- Client-side services go in
{AppName}.Client/Program.cs. - Server-side services go in
{AppName}/Program.cs.
Environment constraints
- Interactive components run in the browser via WebAssembly. No
HttpContext, no server file system. - Static SSR pages in the server project have full server access.
- The .NET runtime (~10 MB) is downloaded to the browser on first visit and cached.
Don'ts
- Don't put interactive components in the server project — they work during prerender but fail after WebAssembly handoff.
- Don't inject
DbContextor server-only services in.Clientproject components — use HTTP APIs instead. - Don't set
@rendermodeon<Routes>inApp.razor— that makes it global. Per-page mode means individual components opt in. - Don't add
@rendermodeto Identity/Account pages if auth is configured — they must stay static SSR.
{
"version": "0.1.0",
"category": "Core",
"compatibility": "Requires a .NET repository or solution."
}