diff --git a/docs/en/Community-Articles/2026-06-02-how-to-implement-multitenancy-in-abp/Post.md b/docs/en/Community-Articles/2026-06-02-how-to-implement-multitenancy-in-abp/Post.md new file mode 100644 index 0000000000..ae8aae7dbd --- /dev/null +++ b/docs/en/Community-Articles/2026-06-02-how-to-implement-multitenancy-in-abp/Post.md @@ -0,0 +1,148 @@ +Multi-tenancy sounds simple until the first data leak, migration issue, or noisy-neighbor incident shows up. The hard part is not adding a `TenantId` column. The hard part is enforcing isolation consistently across authentication, data access, caching, logging, and operations. + +If you are building with ABP, the good news is that multi-tenancy is already a first-class concept. You still need to choose the right architecture and apply a few guardrails, but ABP removes much of the plumbing. + +## Start with the right tenancy model + +There are three common approaches: + +### 1. Shared database, shared schema +All tenants use the same tables, usually separated by a `TenantId` column. + +Use this when: +- You want the simplest setup +- Cost matters more than strict isolation +- You expect many small tenants + +Watch out for: +- Missing tenant filters +- Noisy-neighbor performance issues +- Harder compliance stories + +### 2. Shared database, separate schemas +Each tenant gets its own schema in the same database. + +Use this when: +- You need better isolation than shared tables +- Your database supports schema-based separation well + +Watch out for: +- More complex migrations +- Operational overhead as tenant count grows + +### 3. Database per tenant +Each tenant gets its own database. + +Use this when: +- You need strong isolation +- Compliance or data residency matters +- Some tenants pay for premium isolation + +Watch out for: +- Higher cost +- More deployment and migration work +- More monitoring complexity + +In practice, many SaaS products start with shared schema and move large tenants to dedicated databases later. + +## How ABP helps + +ABP has built-in multi-tenancy support based on the current tenant context. The usual flow is: + +- Resolve the current tenant from subdomain, domain, header, or user context +- Store tenant information in the current unit of work +- Automatically filter tenant-owned entities +- Optionally use separate connection strings per tenant + +For tenant-owned entities, implement ABP's multi-tenant contract so the framework can apply filtering automatically. + +```csharp +public class Product : FullAuditedAggregateRoot, IMultiTenant +{ + public Guid? TenantId { get; set; } + public string Name { get; set; } + + protected Product() {} + + public Product(Guid id, string name, Guid? tenantId) + : base(id) + { + Name = name; + TenantId = tenantId; + } +} +``` + +That gives you a strong default for shared-schema applications. + +## Tenant resolution and authentication + +A multi-tenant app must know who the tenant is before it touches business data. + +Common strategies: +- Subdomain: `tenant1.myapp.com` +- Custom domain: `app.customer.com` +- Header: useful for APIs +- Login-time selection: common in back-office apps + +In ABP, tenant resolution can be configured through contributors. Keep it predictable and avoid mixing too many strategies unless you really need them. + +Also make sure: +- Tenant ID is included securely in claims when appropriate +- Authorization is scoped per tenant +- Admin users cannot accidentally cross tenant boundaries + +## Data isolation rules that matter + +No matter which model you choose, these rules are worth treating as non-negotiable: + +- Always propagate tenant context through application and background jobs +- Include tenant ID in logs and traces +- Index `TenantId` in shared-schema tables +- Add rate limits or quotas for heavy tenants +- Encrypt data at rest and in transit + +If you use shared schema, database-level protections such as row-level security can add another safety net. Application filters are good. Defense in depth is better. + +## Separate database per tenant in ABP + +ABP also supports tenant-specific connection strings. That makes database-per-tenant possible without rewriting your application model. + +Typical setup: +- Keep host data in the main database +- Store tenant connection strings in tenant management +- Resolve the current tenant +- Let ABP switch to the tenant database automatically + +This is a good fit when you want one codebase but stronger tenant isolation. + +## When to use and when not to use + +### Use multi-tenancy when +- You are building a SaaS product for multiple customers +- Tenants need isolated users, roles, and data +- You want one platform with centralized deployment + +### Do not use it when +- You only have one customer environment +- Every customer requires fully custom code and infrastructure +- Your team is not ready to operate tenant-aware monitoring, migrations, and support + +## Common mistakes + +A few mistakes show up repeatedly: + +- Adding multi-tenancy too late +- Relying only on UI-level filtering +- Writing tenant-specific `if` statements everywhere instead of configuration or features +- Forgetting tenant context in background workers and integration events +- Having no migration path from shared to dedicated databases + +ABP helps with the framework side, but architecture decisions are still yours. + +## TL;DR + +- Start with shared schema unless compliance or isolation requirements push you further. +- In ABP, use `IMultiTenant`, tenant resolution, and built-in data filters. +- For stronger isolation, use tenant-specific connection strings and move to database per tenant. +- Always treat tenant context, logging, indexing, and authorization as core design concerns. \ No newline at end of file diff --git a/docs/en/Community-Articles/2026-06-02-how-to-implement-multitenancy-in-abp/cover.png b/docs/en/Community-Articles/2026-06-02-how-to-implement-multitenancy-in-abp/cover.png new file mode 100644 index 0000000000..0987177bf4 Binary files /dev/null and b/docs/en/Community-Articles/2026-06-02-how-to-implement-multitenancy-in-abp/cover.png differ