blazor
Blazor Server + Vertical Slice Architecture
Implement and evolve Blazor Server apps using vertical slices (feature-first), not layered architecture. Organize code by use case so each slice owns its UI, application logic, and data access. High cohesion inside a slice, low coupling between slices.
Target stack: modern .NET 8+ Blazor Server / Blazor Web App (Server). Prefer feature folders over Controllers/Services/Repositories layers. Avoid "god" services or generic repositories unless there is a proven cross-cutting need.
Project structure
- Top-level
Featuresfolder (or equivalent). - Under
Features, one folder per feature or use case:Features/Users/GetUserListFeatures/Users/UserDetailsFeatures/Events/ViewCreatedEvent
- Each feature folder contains everything specific to that use case:
- Blazor components / pages (
.razor, partial.razor.cs). - Request / command / query types and response / view models.
- Handler(s) — MediatR request handlers or an equivalent application-service class — implementing the business logic.
- Slice-specific helpers (mappers, validators) that are not truly cross-cutting.
- Blazor components / pages (
For a complete end-to-end example (component + query + handler + view model), see example-slice.md.
UI rules
- Place the main page/component for a use case in its feature folder, not in a global
Pages/Componentsfolder. Co-locate@pagedirectives and route attributes there. - Treat UI as thin: binding, navigation, and dispatching requests — not business rules or complex data access.
- UI calls into a handler (via
IMediatoror a slice-local application service), passing well-defined request objects and rendering returned view models. - Keep interaction state (current page, selected filters, etc.) in the component. Push business rules and data retrieval into the slice's handler.
- Use DI for
IMediatoror the slice's application service. Do not inject generic "service" types from a shared service layer unless they are truly cross-cutting. - Prefer SSR pages/components with interactive render modes where applicable.
Handlers and domain logic
- Each use case gets its own request type and handler (e.g.
GetUserListQuery+GetUserListHandler). - Handlers orchestrate the use case. They can inject
DbContextor small domain services directly instead of going through a generic service layer. - Request/response types and view models are per-slice. Do not create "one DTO to rule them all" unless it is truly shared and stable.
Data access
- Straightforward EF Core in handlers (or equivalent), projecting directly to view models where appropriate.
- Avoid generic repositories or service layers by default. Introduce shared abstractions only when multiple slices clearly need them and the abstraction is well-understood.
Shared code
- Narrowly scoped:
Infrastructure/Database/AppDbContext,Sharedfor layout, primitive UI components, and simple utilities. - Keep shared code small and generic. Do not move feature-specific logic into
Shared.
When implementing a new requirement
- Restate the requirement in terms of one or more vertical slices.
- Propose which feature folders and files to create or modify. Prefer a new slice over modifying unrelated slices.
- If the codebase is currently layered, introduce vertical slices incrementally — wire up a new feature folder end-to-end rather than attempting a large refactor.
- Ask targeted clarifying questions when ambiguous: where in the domain this feature belongs, whether it is a new slice or extends an existing one, and any domain rules that affect handler logic.
Non-negotiables
- Do not introduce Clean, Onion, or Hexagonal architecture styles unless the user explicitly asks for them alongside vertical slices.
- Default to idiomatic C#, EF Core, and Blazor patterns for .NET 8+.
If any existing instructions in this repository conflict with this skill, follow the repository-specific instructions first and apply these vertical-slice rules as closely as possible.
More from jonhilt/practical-engineer
tdd
Implement one theory through strict outside-in TDD, deriving tests from the spec brief. Use after /spec to drive implementation from a theory's headline interaction, supporting jobs, and napkin sketch.
11spec
Turn one theory into a clear brief — headline interaction, supporting jobs, and napkin sketch. The bridge between a theory and TDD. Use after /theories to specify one theory at a time.
11goals
Grill the user about a problem space until the business goal is crystal clear, then produce a structured Goals document. Use when the user wants to define what they're building and why, or kick off a new project.
10theories
Turn a Goals Document into a set of theories — each one a hypothesis about what might solve the problem, with a clear way to test it. Use after /goals to decide what to build and why.
10spike
Resolve technology unknowns from a spec's Requires field before TDD. Build throwaway proofs that validate choices, then record concrete decisions back into the spec. Use after /spec, before /tdd.
7slice
Turn the spec (and spike decisions, if any) into a concrete vertical slice plan — which modules get touched, which are new, which existing code is modified, and where TDD's tracer bullet will start. Use after /spec (or /spike) and before /tdd.
5