Skip to content

Multi-Tenancy — Overview

Granit.MultiTenancy provides a complete multi-tenancy stack for SaaS applications. A pipeline of pluggable resolvers extracts the tenant from HTTP requests, sets an AsyncLocal context for the entire request, and downstream modules — persistence, caching, messaging — automatically scope their operations to the active tenant.

  • Zero manual WHERE clauses — EF Core query filters handle tenant isolation transparently
  • Four built-in resolvers — subdomain, header, JWT claim, query string
  • Three isolation strategies — shared database, schema-per-tenant, database-per-tenant — switchable per tenant at runtime
  • Cache key isolation — automatic TenantId prefix on all FusionCache keys
  • Host/tenant schema separation — configurable via appsettings.json
  • Message propagation — Wolverine automatically carries tenant context across async boundaries
  • Automatic provisioning — new tenants get schema creation, EF Core migrations, and data seeding out of the box
  • Granit.MultiTenancy — Resolvers, CurrentTenant, middleware
  • Granit.MultiTenancy.EntityFrameworkCore — Tenant store, EF Core persistence
  • Granit.MultiTenancy.Endpoints — Tenant admin API endpoints
  • Granit.Persistence.EntityFrameworkCore — Isolation strategies, GranitDbDefaults, SchemaEnsurer
  • Granit.MultiTenancy.Provisioning — Automatic tenant provisioning handler
  • Granit.Caching — TenantAwareFusionCache decorator
PackageRole
Granit.MultiTenancyResolvers, CurrentTenant, middleware, options
Granit.MultiTenancy.EntityFrameworkCoreITenantReader/ITenantWriter, tenant aggregate, EF persistence
Granit.Persistence.EntityFrameworkCoreGranitDbDefaults, SchemaEnsurer, isolation strategy factories
Granit.MultiTenancy.ProvisioningTenantProvisioningHandler — automatic tenant provisioning on creation
Granit.Persistence.EntityFrameworkCore.HostingITenantProvisioner, AutoTenantProvisioner — schema + migration + seeding
Granit.CachingTenantAwareFusionCache — automatic cache key isolation
flowchart TB
    subgraph HTTP["HTTP Pipeline"]
        REQ[Request] --> RES[Resolver Pipeline]
        RES --> CTX["ICurrentTenant (AsyncLocal)"]
    end

    subgraph DATA["Data Layer"]
        CTX --> EF["EF Core Query Filters"]
        CTX --> CACHE["TenantAwareFusionCache"]
        CTX --> WV["Wolverine Context Propagation"]
    end

    subgraph ISOLATION["Isolation Strategy"]
        EF --> SD[SharedDatabase<br/>WHERE TenantId = @id]
        EF --> SPT[SchemaPerTenant<br/>SET search_path]
        EF --> DPT[DatabasePerTenant<br/>per-tenant connection]
    end
[DependsOn(typeof(GranitMultiTenancyModule))]
public class AppModule : GranitModule { }
{
"MultiTenancy": {
"IsEnabled": true,
"DomainTemplate": "{0}.myapp.com"
},
"TenantIsolation": {
"Strategy": "SchemaPerTenant",
"HostSchema": "host"
}
}
app.UseAuthentication();
app.UseGranitMultiTenancy(); // After auth, before authorization
app.UseAuthorization();

This section covers multi-tenancy in depth:

  • Tenant Resolvers — the four built-in resolvers and how to add custom ones
  • Isolation Strategies — shared database, schema-per-tenant, database-per-tenant, and the hybrid model
  • Host vs Tenant — how to separate host infrastructure from tenant data using GranitDbDefaults
  • Cache Isolation — automatic tenant-scoped cache keys with TenantAwareFusionCache
  • Automatic Provisioning — zero-config schema creation, migrations, and seeding for new tenants