# FullStackHero .NET 10 Starter Kit: A Modular Multitenant SaaS Boilerplate

> The FullStackHero starter kit ships a .NET 10 modular monolith plus two React 19 clients, with multitenancy, billing and observability already wired. Here is what the repository actually contains, how to scaffold it, and where the trade-offs sit.

**fullstackhero/dotnet-starter-kit** — Production Grade Cloud-Ready .NET 10 Starter Kit (Web API + React Client) with Multitenancy Support, and Clean/Modular Architecture that saves roughly 200+ Development Hours! All Batteries Included.

- Repository: https://github.com/fullstackhero/dotnet-starter-kit
- Website: https://fullstackhero.net/
- Stars: 6,806 · Forks: 2,004
- Language: C#
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/fullstackhero-dotnet-starter-kit

## What the FullStackHero starter kit actually saves you from writing

The problem this targets is not authentication. Plenty of templates give you a login page. The problem is the set of concerns that appear only once a product has more than one paying customer: resolving which tenant a request belongs to, keeping tenant data apart in the same database, provisioning a tenant and running migrations for it, issuing and refreshing tokens with fine-grained permissions, recording an audit trail, running background jobs, storing files behind presigned URLs, and emitting traces and metrics you can actually query. The README frames the kit as the boring, hard parts already done right, and lists identity, multitenancy, billing, auditing, webhooks, files, chat, real-time, caching, jobs, storage, OpenAPI and OpenTelemetry as wired and tested.

The audience is a team starting a multi-tenant SaaS on .NET that does not want to spend the first month on plumbing. It is a poor fit for a single-tenant internal tool, and it is a poor fit for anyone who wants to pick each dependency themselves, because the choices are already made: PostgreSQL, Valkey, MinIO, Hangfire, Finbuckle, Mediator, React 19 with TanStack Query and Tailwind. The kit is opinionated in the way a framework is opinionated, and the README is explicit that you get the complete detached source with real project references rather than a hidden NuGet runtime, so the opinions are editable rather than locked.

## Modular monolith with vertical slices and a .Contracts boundary

The backend is a modular monolith, not microservices and not a layered onion. Each bounded context is a runtime project plus a .Contracts project, and the README states that the .Contracts project is its only public surface. That single rule is what makes the modularity enforceable instead of aspirational: a module cannot reach into another module's internals because the internals are not referenced. The README says the boundaries are checked by architecture tests using NetArchTest, which means an accidental reference fails a build rather than a code review.

Inside a module the style is vertical slices. Requests arrive at Minimal APIs, are dispatched through Mediator, which the README describes as source-generated CQRS, and validated with FluentValidation. Persistence is EF Core 10 on PostgreSQL through Npgsql, with domain events, a specification pattern, soft-delete and audit interceptors, and tenant-isolated DbContexts. Cross-cutting behaviour sits outside the slices: HybridCache on Valkey, Hangfire for jobs, presigned S3 or MinIO storage, mailing, idempotency, quotas, rate limiting, API versioning, and RFC 9457 ProblemDetails for errors. Observability is Serilog plus OpenTelemetry for traces, metrics and logs, with health probes and security and exception auditing.

The module list is Identity, Multitenancy, Billing, Catalog, Tickets, Chat, Files, Webhooks, Auditing and Notifications. Catalog and Tickets look like samples rather than product features, so expect to delete or rewrite them. That is normal for a starter kit and worth planning for: the first real task on a new project is usually removing the example domains, not adding to them.

## Multitenancy is the reason to pick this over a generic template

Tenant handling comes from Finbuckle, and the README describes tenant resolution, provisioning, per-tenant migrations and seeding, with isolation enforced by default. The phrase enforced by default is the interesting part. In most codebases, tenant filtering is a convention that a new query can silently break. Here the isolation lives in the DbContext layer alongside the soft-delete and audit interceptors, so it applies to queries that go through the context rather than to queries a developer remembered to filter.

The provisioning path is where this design shows its shape. Migrations are never run at API startup, according to the README, which instead provides a one-shot DbMigrator project. That is a deliberate operational choice: the API host stays stateless with respect to schema, and schema changes become an explicit deploy step you can run once per environment. It also means a per-tenant migration story has somewhere to live. The cost is that you cannot simply start the API against an empty database and expect it to work; something has to run the migrator first, and the Aspire AppHost handles that locally.

I would treat the multitenancy layer as the load-bearing feature and everything else as convenience. If your product is single-tenant, the tenant resolution, per-tenant seeding and tenant-isolated contexts are overhead you will spend time removing.

## Installing the fsh CLI and getting the whole stack running

There are three documented paths. The README recommends the fsh CLI, which is distributed as the FullStackHero.CLI NuGet tool, and the template is also published as FullStackHero.NET.StarterKit for dotnet new. The prerequisites the README lists are the .NET 10 SDK, Docker for Postgres, Valkey and MinIO through Aspire, and Node 20 or later for the React apps.

Install the CLI globally, then run the environment check before scaffolding anything. The README shows fsh doctor as verifying your SDK, Docker, Aspire and ports, which is the fastest way to find out that a port is already taken or Docker is not running.

```bash
dotnet tool install -g FullStackHero.CLI
fsh doctor
```

Then scaffold. The wizard is interactive, and the README gives non-interactive flags for the three shapes it supports: full stack with Postgres, backend only, or a minimal API with a migrator and no Aspire or front-end.

```bash
fsh new MyApp --non-interactive
fsh new MyApp --no-frontend
fsh new MyApp --no-aspire --no-frontend
```

Run the AppHost to bring up the API, both React apps, Postgres, Valkey and MinIO in one command. The README states this starts the whole stack.

```bash
dotnet run --project src/Host/MyApp.AppHost
```

The README gives the addresses to expect: the Aspire dashboard at https://localhost:15888, the API with Scalar docs at https://localhost:7030/scalar, the admin app at http://localhost:5173 and the dashboard app at http://localhost:5174. Sign in with a seeded demo account, which the README gives as admin@acme.com with the password Password123!. If you cloned the repository instead of scaffolding, the README uses the project name FSH.Starter, so the AppHost path is src/Host/FSH.Starter.AppHost.

## Two React clients, runtime config, and what the front-end assumes

The front-end is not a single admin panel. There are two React 19 apps under clients: admin, described as the operator console, and dashboard, described as the tenant app. Both are React 19 with Vite 7 and TypeScript, TanStack Query v5 for data, React Router 7 for routing, Radix and Tailwind v4 in a shadcn-style setup, and real-time over SignalR or SSE. Testing is Playwright, and the README puts the front-end E2E count at over 200.

One detail deserves attention because it affects deployment more than it looks. Configuration is read at runtime from /config.json, so the same build can be promoted between environments without a rebuild. That is a meaningful difference from the usual Vite pattern of baking VITE_ variables in at build time, and it means your deploy pipeline needs to write config.json per environment rather than set build arguments. The README also notes the API client is hand-written and typed rather than generated, which keeps the client readable but puts the burden of staying in sync with the API on you.

The practical consequence is that adopting this kit commits you to a two-app front-end split. If your product has one audience, you will be maintaining a second Vite app, its routing, its Playwright suite and its config for no reason.

## Deployment paths and the operational pieces you inherit

The README describes three deployment-related artefacts: a Docker Compose production stack under deploy/docker, Terraform for AWS under deploy/terraform, and an API image published to GHCR. Local orchestration is .NET Aspire, which the README says brings up Postgres with pgAdmin, Valkey with RedisInsight, MinIO, the migrator, the demo seeder, the API and both React apps. CI is path-scoped for backend and frontend, and the README states warnings are treated as errors.

The infrastructure choices are the part most likely to conflict with an existing platform team. If your organisation runs Kubernetes with an operator-managed Postgres and a managed Redis, the Compose file and the Terraform module are reference material rather than something you deploy unchanged. The Terraform targets AWS specifically, so a GCP or Azure shop is reading it for structure, not using it. Nothing in the README suggests provider-neutral infrastructure.

The DbMigrator is the piece I would check first in any real deployment. Because migrations are never run at API startup, your release process needs an explicit step that runs the migrator before the new API version takes traffic. The README does not document rollback, so a failed migration is a situation you will have to plan for yourself.

## Testing, licence and the cost of keeping up

The README claims over 1,600 backend tests using xUnit, Shouldly, NSubstitute, AutoFixture, NetArchTest for boundaries and Testcontainers for integration work, plus over 200 Playwright E2E tests on the front-end. Testcontainers means the integration tests need Docker, which is worth knowing before you wire them into a CI runner that does not have it.

The licence is MIT, which is permissive and places few obligations on how you redistribute or modify the code. The README emphasises that you receive the complete source with real project references and no hidden NuGet runtime, so there is nothing to eject later. That matters for licence reasoning in one specific way: you are not depending on a runtime package whose terms could change under you, because the code is in your repository. This is a description of the licence, not legal advice, and the usual caveat applies that bundled third-party dependencies carry their own terms.

Maintenance cost is the real question. The repository's last push was on 2026-08-08, and the most recent release is 10.0.0 from 2026-06-19. Version 10.0.0 tracks .NET 10, and the jump from the 2.0.4-rc release in 2024 to 10.0.0 in 2026 indicates the project renumbered to follow the .NET major version. Practically, that means upgrade cadence is tied to .NET releases, and the fsh CLI exposes an update command alongside new, doctor, info and --version. Because you own the source, an upgrade is a merge you perform, not a package restore, and that is the ongoing cost: every .NET major version is a merge across Identity, Multitenancy, Billing, Catalog, Tickets, Chat, Files, Webhooks, Auditing and Notifications, plus two React apps.

## Conclusion

Adopt it if you are building a multi-tenant SaaS on .NET and want identity, tenant isolation, billing, jobs and observability present as readable source rather than as packages to assemble. Skip it if you want a small API with no tenant model, no React clients and no Docker or Aspire dependency, because the scaffolding will be dead weight you have to strip out. Before committing, run fsh new MyApp into a throwaway directory and check three things: that fsh doctor reports your SDK, Docker and ports as usable, that the seeded demo account signs in at the admin app on port 5173, and that the DbMigrator project, not the API host, is what applies migrations in your deploy path. If any of those three fails, the rest of the kit is not worth evaluating.

## FAQ

### Is the FullStackHero .NET starter kit free?

Yes. The repository is licensed under MIT, and the README states you receive the complete detached source with real project references rather than a hidden runtime package. The fsh CLI and the dotnet new template are distributed as NuGet packages.

### How do I download and install the FullStackHero .NET starter kit?

Install the CLI with dotnet tool install -g FullStackHero.CLI, run fsh doctor to check your environment, then scaffold with fsh new MyApp. The README also documents dotnet new install FullStackHero.NET.StarterKit followed by dotnet new fsh -n MyApp, and cloning the repository directly.

### What are the prerequisites for running the FullStackHero starter kit?

The README lists the .NET 10 SDK, Docker for Postgres, Valkey and MinIO through Aspire, and Node 20 or later for the React apps. The fsh doctor command is documented as verifying your SDK, Docker, Aspire and ports.

### Does the FullStackHero starter kit support multitenancy?

Yes, multitenancy is handled through Finbuckle, and the README describes tenant resolution, provisioning, per-tenant migrations and seeding, with isolation enforced by default. Tenant-isolated DbContexts sit alongside soft-delete and audit interceptors in the EF Core layer.

### Are database migrations run automatically when the API starts?

No. The README states that migrations are never run at API startup and that the kit provides a one-shot DbMigrator project instead. In the local Aspire setup the migrator runs as part of the orchestrated stack.

## Sources

- [fullstackhero/dotnet-starter-kit on GitHub](https://github.com/fullstackhero/dotnet-starter-kit)
- [License: MIT](https://github.com/fullstackhero/dotnet-starter-kit/blob/main/LICENSE)
- [Project website](https://fullstackhero.net/)
- [README](https://github.com/fullstackhero/dotnet-starter-kit/blob/main/README.md)
- [Releases](https://github.com/fullstackhero/dotnet-starter-kit/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fullstackhero-dotnet-starter-kit
