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 deleted file mode 100644 index ae8aae7dbd..0000000000 --- a/docs/en/Community-Articles/2026-06-02-how-to-implement-multitenancy-in-abp/Post.md +++ /dev/null @@ -1,148 +0,0 @@ -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 deleted file mode 100644 index 0987177bf4..0000000000 Binary files a/docs/en/Community-Articles/2026-06-02-how-to-implement-multitenancy-in-abp/cover.png and /dev/null differ