A modern .NET 10 full-stack project template for building multi-tenant SaaS applications with Vertical Slice Architecture (VSA), Hybrid Blazor, and AI-friendly structure.
Krafter is used via
dotnet new.You do not clone this repository to start an application. Clone it only if you want to contribute to the template itself.
# 1. Install the template pack (one-time)
dotnet new install AditiKraft.Krafter.Templates
# 2. Create a new app
dotnet new krafter -n MyApp # Split Host (separate API + UI)
dotnet new krafter-single -n MyApp # Single Host (combined)
# 3. Run it
cd MyApp
dotnet run --project aspire/MyApp.Aspire.AppHost/MyApp.Aspire.AppHost.csprojKrafter ships as a dotnet new template pack with two hosting models:
| Template | Command | Best for |
|---|---|---|
| Split Host | dotnet new krafter -n MyApp |
Separate Backend API + Blazor UI, clearer service boundaries, independent scaling |
| Single Host | dotnet new krafter-single -n MyApp |
Combined API + UI, simpler deployment, fewer moving parts |
Always use
-nto set your project name — it replaces namespaces, folders, and project files throughout the generated solution.
When should I choose each variant?
Choose Split Host (krafter) when:
- You want to scale API and UI independently
- Different teams own backend vs frontend
- You expect additional clients such as mobile apps or CLIs
- You prefer explicit service boundaries
Choose Single Host (krafter-single) when:
- You want the simplest possible deployment
- You prefer a single process and a single Aspire resource
- You want lower operational overhead
- Your team owns the full stack end to end
dotnet new install AditiKraft.Krafter.Templates # Install
dotnet new update # Update to latest
dotnet new uninstall AditiKraft.Krafter.Templates # UninstallTry the live demo at https://krafter.getkrafter.dev/
Default Credentials:
- Email:
[email protected] - Password:
123Pa$$word!
Alternatively, log in with Google to create a new account.
Krafter is a production-ready .NET 10 application template, not a starter toy project. It gives you a structured foundation for full-stack business apps with modern defaults already wired together.
| Area | What you get |
|---|---|
| Architecture | Vertical Slice Architecture (VSA), feature-based organization, Minimal APIs, clean separation between Contracts, Backend, and UI |
| Frontend | Hybrid Blazor (WebAssembly + Server), Radzen UI components, code-behind pattern, responsive layouts, theming support |
| Security | JWT authentication, Google OAuth, permission-based authorization, token refresh, ASP.NET Core Identity |
| Multi-tenancy | Tenant-aware design with database-level isolation patterns |
| Data | Entity Framework Core 10, PostgreSQL / MySQL support, migrations, soft delete, multiple database contexts |
| Realtime & jobs | SignalR for live updates, TickerQ for background processing |
| API consumption | Refit-based type-safe HTTP clients with token handling |
| Observability | .NET Aspire, OpenTelemetry, health checks, structured logging |
| Delivery | Docker support, NUKE build automation, GitHub Actions workflows |
- Template-first workflow with
dotnet new - Feature-oriented backend structure that is easier to extend with AI assistance
- Modern full-stack .NET setup without spending days on wiring
- Two hosting models so you can optimize for simplicity or separation
- Built-in patterns for auth, tenants, jobs, realtime, and observability
The diagrams below reflect the template structure and are useful before you generate or contribute to a project.
This section applies to a generated project created with
dotnet new krafterordotnet new krafter-single.If you want to work on the template repository itself, jump to Contributing & Template Development.
- .NET 10 SDK
- Docker Desktop (for Aspire/PostgreSQL)
- Visual Studio 2022 17.11+ or VS Code
-
Create a project from the template
dotnet new krafter -n MyApp cd MyApp -
Start the AppHost
dotnet run --project aspire/MyApp.Aspire.AppHost/MyApp.Aspire.AppHost.csproj
-
Let
myapp-migratorfinish before judging startup health- The AppHost starts the short-lived migrator before the main app resources
- For normal startup, you do not need to run
dotnet ef database updatemanually
-
Open the generated app
- Aspire Dashboard: https://localhost:17285
- Backend API (split host only): https://localhost:5199
- Scalar API Reference (split host only): https://localhost:5199/scalar/v1
- Blazor UI: https://localhost:7291
-
Sign in with the seeded admin account
- Email:
[email protected] - Password:
123Pa$$word!
Alternatively, log in with Google, which will create a new account.
- Email:
⚠️ Change the default password immediately in production.
Database migrations workflow
AppHost applies checked-in migrations automatically through krafter-migrator. In normal local development, start AppHost and let the migrator complete.
The existing ConnectionStrings:KrafterDbMigration value in src/AditiKraft.Krafter.Backend/appsettings.Local.json already works for dotnet ef migrations add. Do not change it.
Install EF Core tools once if needed:
dotnet tool install --global dotnet-efCreate a migration from the Backend project:
cd src/AditiKraft.Krafter.Backend
dotnet ef migrations add <MigrationName> --context KrafterContext
dotnet ef migrations add <MigrationName> --context TenantDbContext
dotnet ef migrations add <MigrationName> --context BackgroundJobsContextThen restart AppHost to apply it:
dotnet run --project aspire/AditiKraft.Krafter.Aspire.AppHost/AditiKraft.Krafter.Aspire.AppHost.csprojTroubleshooting
| Issue | Cause | Solution |
|---|---|---|
| "Unable to create DbContext" | Missing ConnectionStrings:KrafterDbMigration or wrong working directory |
Restore the KrafterDbMigration entry in appsettings.Local.json and run the command from src/AditiKraft.Krafter.Backend |
"krafter-api does not start" |
krafter-migrator failed first |
Check the krafter-migrator logs and fix the migration error |
| "Migration already exists" | Duplicate migration name | Use dotnet ef migrations remove --context <ContextName> |
| "Pending model changes" | The model changed but no migration exists yet | Add a new migration for the affected context before restarting AppHost |
dotnet-ef not found |
EF tools not installed | Run dotnet tool install --global dotnet-ef |
Configuration notes
Local development works with the checked-in dev settings.
Only change configuration if you need custom values for:
- PostgreSQL container credentials in
aspire/AditiKraft.Krafter.Aspire.AppHost/appsettings.json - JWT, TickerQ, or Google auth settings in
src/AditiKraft.Krafter.Backend/appsettings.json - UI backend URL or Google client settings in
src/UI/AditiKraft.Krafter.UI.Web/appsettings.Development.jsonandsrc/UI/AditiKraft.Krafter.UI.Web.Client/wwwroot/appsettings.json
For anything outside local development, prefer user-secrets or environment variables instead of committed values.
The structure below is what you get after running dotnet new krafter -n MyApp (split host). Single host is identical except Backend has no Program.cs.
MyApp/
├── Agents.md # AI agent instructions (entry point)
├── aspire/ # Aspire orchestration
│ ├── MyApp.Aspire.AppHost/
│ └── MyApp.Aspire.ServiceDefaults/
├── src/
│ ├── MyApp.Contracts/ # Shared contracts library
│ │ ├── Contracts/ # Auth, Users, Roles, Tenants DTOs
│ │ ├── Common/ # Routes, permissions, shared models
│ │ └── Realtime/ # SignalR method contracts
│ ├── MyApp.Backend/ # ASP.NET Core API (VSA)
│ │ ├── Web/ # HTTP pipeline, middleware, auth config
│ │ ├── Features/ # Vertical slices
│ │ ├── Infrastructure/ # Jobs, notifications, persistence, realtime
│ │ ├── Common/ # Context, entities, interfaces, extensions
│ │ ├── Errors/ # Exception types
│ │ ├── Migrations/ # EF Core migrations
│ │ └── Program.cs # (split host only)
│ ├── MyApp.Backend.Migrator/ # Short-lived EF migration runner
│ └── UI/
│ ├── MyApp.UI.Web.Client/ # Blazor WebAssembly
│ │ ├── Features/
│ │ ├── Infrastructure/ # AuthApi, Refit, SignalR, Storage, Http
│ │ └── Common/ # Shared components, models
│ └── MyApp.UI.Web/ # Blazor Server host (or combined host in single mode)
├── build/ # NUKE build automation
├── docs/ # Documentation assets
├── .github/ # GitHub Actions workflows
└── README.md
If you are using Krafter to build an app, the main workflow is:
- Generate a project with
dotnet new krafterordotnet new krafter-single - Run the AppHost
- Add features in the existing Contracts / Backend / UI structure
- Create migrations when your model changes
- Let the migrator apply them on the next AppHost start
For detailed feature-by-feature instructions, naming conventions, and backend/UI implementation rules, use Agents.md and the related files in:
src/AditiKraft.Krafter.Backend/src/UI/src/AditiKraft.Krafter.Contracts/
# Build all projects (template development)
dotnet build AditiKraft.Krafter.Dev.slnx
# Run tests
dotnet test
# Create migrations
dotnet ef migrations add <Name> --project src/AditiKraft.Krafter.Backend --context KrafterContext
dotnet ef migrations add <Name> --project src/AditiKraft.Krafter.Backend --context BackgroundJobsContext
dotnet ef migrations add <Name> --project src/AditiKraft.Krafter.Backend --context TenantDbContext
# Apply migrations through the dedicated migrator
dotnet run --project aspire/AditiKraft.Krafter.Aspire.AppHost/AditiKraft.Krafter.Aspire.AppHost.csprojBuild container images with:
dotnet publish src/AditiKraft.Krafter.Backend/AditiKraft.Krafter.Backend.csproj -c Release -p:PublishProfile=DefaultContainer
dotnet publish src/UI/AditiKraft.Krafter.UI.Web/AditiKraft.Krafter.UI.Web.csproj -c Release -p:PublishProfile=DefaultContainerThe project includes GitHub Actions workflows for:
- Building and testing on every push
- Creating Docker images for
mainanddevbranches - Pushing images to GitHub Container Registry
- Triggering deployment webhooks
See .github/workflows for configuration.
Clone this repository only if you want to work on the Krafter template itself.
If you want to create an application, use
dotnet new krafterordotnet new krafter-single.
git clone https://github.com/AditiKraft/Krafter.git
cd Krafter
dotnet restoreTemplate repo structure (beyond the generated output)
The template repository contains extra folders that are not included in generated projects:
AditiKraft.Krafter/ # Template repo root
├── .template.config/ # Split-host template definition
├── .template.config-single/ # Single-host template definition
├── src-single/ # Single-host overrides (Program.cs, csproj, appsettings)
│ └── UI/AditiKraft.Krafter.UI.Web/ # Overlaid into src/UI/ during template generation
├── aspire-single/ # Single-host Aspire AppHost override
│ └── AditiKraft.Krafter.Aspire.AppHost/ # Overlaid into aspire/ during template generation
├── Agents.md # Template developer instructions
├── Agents.split.md # Renamed to Agents.md in split-host output
├── Agents.single.md # Renamed to Agents.md in single-host output
├── AditiKraft.Krafter.Dev.slnx # All projects (template development)
├── AditiKraft.Krafter.slnx # Split-host solution (template output)
├── AditiKraft.Krafter.Single.slnx # Single-host solution (template output)
├── AditiKraft.Krafter.Templates.csproj # NuGet template packaging
└── pack-and-install.cmd # Local pack + install helper
# Split-host solution (default)
dotnet run --project aspire/AditiKraft.Krafter.Aspire.AppHost/AditiKraft.Krafter.Aspire.AppHost.csproj
# Single-host solution
dotnet run --project aspire-single/AditiKraft.Krafter.Aspire.AppHost/AditiKraft.Krafter.Aspire.AppHost.csproj# Pack the template
dotnet pack AditiKraft.Krafter.Templates.csproj -o ./nupkg
# Install from local pack
dotnet new install ./nupkg/AditiKraft.Krafter.Templates.*.nupkg
# Create test projects
dotnet new krafter -n TestApp -o ../TestApp
dotnet new krafter-single -n TestSingle -o ../TestSingle- Follow the coding conventions in Agents.md and the relevant sub-project
Agents.mdfiles - Open changes through a Pull Request
- Use Conventional Commits
feat(scope): add new feature
fix(scope): fix bug
docs(scope): update documentation
refactor(scope): refactor code
test(scope): add tests
- License: MIT — see LICENSE
- Documentation: Agents.md
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Acknowledgments
- .NET Team - For the amazing .NET platform
- Radzen - For the excellent Blazor components
- Refit - For the type-safe REST client
- NUKE Build - For the build automation framework
Built with ❤️ by Aditi Kraft
⭐ Star this repository if you find it helpful!