Multi-Tenancy
Serve multiple tenants from a single application instance. Automatically resolve the current tenant from subdomain, header, or URL path and scope all data access.
Setup
import "github.com/CodeSyncr/nimbus/tenancy"
app.Use(tenancy.New(tenancy.Config{
Strategy: "subdomain", // subdomain | header | path
Header: "X-Tenant-ID", // only used with "header" strategy
}))
Tenant Resolution Strategies
| Strategy | Resolution | Example |
|---|---|---|
subdomain | Extract from Host header | acme.myapp.com |
header | Custom request header | X-Tenant-ID: acme |
path | URL path prefix | /tenant/acme/... |
Using the Current Tenant
func (ctrl *DashboardController) Index(c *http.Context) error {
tenant := tenancy.FromContext(c.Request.Context())
// Query scoped to tenant
var users []User
db.Where("tenant_id = ?", tenant.ID).Find(&users)
return c.JSON(200, users)
}
Real-Life Example: SaaS Dashboard
// Tenant-scoped product listing
func (ctrl *ProductController) Index(c *http.Context) error {
tenant := tenancy.FromContext(c.Request.Context())
var products []Product
db.Where("tenant_id = ?", tenant.ID).
Order("created_at DESC").
Find(&products)
return c.JSON(200, products)
}
// Tenant-scoped analytics
func (ctrl *AnalyticsController) Revenue(c *http.Context) error {
tenant := tenancy.FromContext(c.Request.Context())
var total float64
db.Model(&Order{}).
Where("tenant_id = ? AND created_at >= ?", tenant.ID, startOfMonth()).
Select("COALESCE(SUM(total), 0)").
Scan(&total)
return c.JSON(200, map[string]float64{"revenue": total})
}
// Tenant-scoped cache keys
func (ctrl *SettingsController) Get(c *http.Context) error {
tenant := tenancy.FromContext(c.Request.Context())
key := fmt.Sprintf("settings:%d", tenant.ID)
settings, _ := cache.RememberT[Settings](key, time.Hour, func() (Settings, error) {
var s Settings
db.Where("tenant_id = ?", tenant.ID).First(&s)
return s, nil
})
return c.JSON(200, settings)
}
Best Practices
- Always scope database queries with
tenant_id - Include tenant ID in cache keys to prevent data leakage
- Use
subdomainfor customer-facing SaaS apps - Use
headerfor API-first architectures - Create GORM scopes to automatically apply tenant filtering