Multi-tenancy, single-tenancy, update strategies, isolation models, and the evolution path for scaling the Clarity platform to hundreds of customers.
Clarity operates a single-tenant, dedicated-instance model. Each customer receives their own Kubernetes namespace ({{acronym}}-{{env}}), database instance, Docker container set (backend, frontend, Redis sidecar), Client layer with customer-specific Startup.cs and overrides, plugin configuration, NFS storage mount, SSL certificate, and subdomain.
The codebase is shared via Docker image tags — all customers run the same backend and frontend images. Customer-specific behavior is driven by:
| Dimension | Single-Tenant Current | Multi-Tenant Shared DB | Multi-Tenant DB-per-Tenant Recommended |
|---|---|---|---|
| Deployment Unit | 1 K8s namespace + DB per customer | 1 shared app + 1 shared DB | 1 shared app + 1 DB per tenant |
| Data Isolation | COMPLETE — separate everything | ROW-LEVEL — TenantId filter required | DATABASE-LEVEL — strong isolation |
| PCI Compliance | STRONGEST — fully isolated PCI environment | WEAKEST — filter bug could leak tokens | STRONG — separate databases |
| Performance Isolation | COMPLETE — no noisy neighbor | NONE without throttling | PARTIAL — DB isolated, app shared |
| Update Speed | N operations (one per customer) | Single deployment, instant | Single deployment + per-tenant migrations |
| Customization | Full (Client layer + hooks + plugin) | Config + feature flags only | Config + feature flags only |
| Cost at Scale | Highest (dedicated compute per customer) | Lowest (shared everything) | Moderate (shared app, dedicated DBs) |
| Provisioning | ~5 minutes (infra + config) | ~30 seconds (DB + registry) | ~30 seconds (DB + registry) |
The Settings system stores customer-specific preferences: payment provider selection, ERP connector, feature toggles, notification rules, surcharge configuration, and branding/theme. All managed through the admin UI without any code changes.
The Client layer registers pre-hooks and post-hooks on any pipeline. Example: a customer needs custom surcharge calculation based on their state's rules — they add a hook on CalculateSurchargePipeline that adjusts the result after default logic runs. Core is untouched. Other customers unaffected.
For truly unique requirements, a ClientPlugin is registered last in Startup.cs. It can override any previously registered service, add new entities, create API endpoints, and inject frontend routes. Because it's registered last, it wins any DI conflicts. Because it's in the Client layer, it ships only with that customer's deployment.
The key insight: Client customizations are ADDITIVE. They hook into pipelines and override services — they never modify Core or Plugin source code. When Core or Plugins are updated via submodule pointers, customizations continue to work as long as pipeline interface contracts are maintained.
Immediate ROI, zero architectural risk
Example: Fortune 500 running D365 F&O with 20 custom pipeline hooks
Example: Mid-market distributor on NetSuite with standard order-to-cash
Example: Small business using basic invoice payments
The same Docker image serves all tiers. The difference is deployment topology, not codebase.
For payments platforms, shared-database multi-tenancy is not recommended. Database-per-tenant provides strong isolation while enabling the operational benefits of a shared application tier.
Application physically cannot access another tenant's DB. Connection string resolved from tenant registry per authenticated request.
Every IPipelineContext includes resolved TenantId. Cross-cutting operations require elevated permissions and are audited.
Belt-and-suspenders: modelBuilder.Entity<BaseEntity>().HasQueryFilter(e => e.TenantId == _currentTenantId) prevents cross-tenant data even if wrong connection string resolved.
Authenticated user's JWT contains TenantId claim. Middleware validates token tenant matches resolved tenant. Mismatch → 403 Forbidden.
Tests provision 2+ tenant databases and verify operations in Tenant A's context NEVER return Tenant B's data.
Flags any database query returning data with TenantId different from request's tenant context.
8 Steps
Infrastructure (~5 min)
Business Config (30-60 min)
4 Steps
Infrastructure (~30 sec)
Business Config (30-60 min)
Tenant Admin Portal: click “Create Customer” → DB provisioned → migrations run → tenant registered → customer receives login link. Pre-loaded templates for common configurations.
| Scenario | Single-Tenant | Multi-Tenant (DB-per-Tenant) |
|---|---|---|
| Security patch | Fleet pipeline pushes new image to all namespaces. Staggered rollout possible. | Single deployment restart. ALL tenants patched immediately. |
| Feature release | New image + migration per customer. Can be staggered across customers. | Single restart + migration runner iterates tenant DBs. Feature flags for gradual enable. |
| Breaking connector change | Only affected customers updated independently. | Feature flag gates new behavior per tenant. |
| Rollback | Roll back individual customer's image tag. Others unaffected. | Roll back entire application. All tenants revert. Can roll back individual tenant DBs separately. |
| Customer requests delay | Pin their deployment to specific commit hash. | Feature flags disable new behavior for that tenant. |
| Emergency hotfix | Deploy patched image to ONLY their namespace. Zero risk to others. | Deploy to shared app — all tenants receive it. OR promote to single-tenant temporarily. |
This is why the hybrid model is recommended: customers with regulatory constraints or code freeze requirements can use single-tenant (Tier 1) for full version control, while standard customers benefit from instant multi-tenant updates.
Every customer receives their own dedicated database instance — your data is physically separate from every other customer, not just logically partitioned within a shared database. On top of that, the platform enforces six layers of isolation: dedicated connection strings per tenant, scoped pipeline context, EF Core global query filters as a safety net, JWT-based tenant claim validation on every request, automated integration tests that verify cross-tenant data cannot leak, and runtime monitoring that alerts on any tenant context mismatch. In today’s single-tenant deployment, each customer also runs in separate application containers, making cross-tenant access physically impossible. Learn more about the defense-in-depth isolation model and our data handling practices.
You stay in full control of your update timeline. In the current single-tenant model, updates are deployed to each customer independently — your environment can be on a different version than any other customer, and deployments can be scheduled around your business calendar, peak seasons, or internal change-management windows. In a multi-tenant deployment, the application is updated once for all tenants, but feature flags provide granular control so new capabilities can be enabled or disabled per customer. Either way, you’re never surprised by unexpected changes. See the full update & rollback strategy.
Absolutely. In a single-tenant deployment, your environment is pinned to a specific version — other customers can move forward while yours stays frozen for as long as needed. When you’re ready, the update is applied and any pending database migrations run automatically. In a multi-tenant deployment, feature flags keep new behavior disabled for your tenant while others receive it. For critical regulatory freezes (like quarter-close or audit periods), a tenant can even be temporarily promoted to a dedicated single-tenant instance for complete version control. See the update & rollback strategy for details.
Today’s infrastructure provisioning is fully automated and completes in approximately 5 minutes — that includes creating the Kubernetes namespace, database, application containers, SSL certificate, and DNS entry. From there, business configuration (connecting your ERP, setting up payment providers, and configuring site settings) typically takes 30–60 minutes in collaboration with your team. As the platform evolves toward multi-tenancy, infrastructure provisioning drops to roughly 30 seconds since only a new database and tenant registry entry are needed. The long-term vision includes a self-service tenant admin portal for near-instant provisioning. See the full onboarding walkthrough.
Clarity uses a three-layer customization model that keeps the core platform unified. Layer 1 — Configuration handles over 80% of customization needs through settings, feature toggles, and branding — no code required. Layer 2 — Pipeline Hooks lets you inject custom logic at any point in a business workflow (before payment capture, after order sync, etc.) without modifying the core engine. Layer 3 — Client Plugin provides a dedicated code project for truly unique requirements like custom entities, service overrides, or additional API endpoints. All three layers are additive and isolated, so core platform updates apply cleanly without breaking any customizations. Learn more about customization layers and pipeline hooks.
We recommend a hybrid model that matches the right deployment tier to each customer’s needs. Enterprise customers with complex customizations, strict compliance requirements, or regulatory obligations receive dedicated single-tenant instances with full version control and isolation. Standard mid-market customers benefit from efficient multi-tenant deployment with database-per-tenant isolation — delivering faster provisioning and lower overhead while maintaining strong data separation. The same platform, codebase, and engineering team serves both tiers seamlessly, with no forks and no divergence. Explore the hybrid tier model for the full breakdown.
Performance isolation is built into every layer. At the database level, each tenant has their own dedicated database instance, so a large data sync or heavy reporting query from one customer never touches another’s resources. At the application tier, per-tenant rate limiting, concurrency caps on ERP connector sync operations, background task quotas, and Kubernetes horizontal pod autoscaling ensure that no single tenant can monopolize shared compute resources. Enterprise customers on dedicated instances have zero noisy-neighbor risk by design. The result: consistent, predictable performance for every customer regardless of what others are doing on the platform.
All connector credentials — ERP API keys, payment gateway tokens, OAuth secrets — are stored exclusively in each customer’s own dedicated database within encrypted Settings entities. There is no shared or centralized credential store. When the platform needs to authenticate to your ERP or payment provider, it resolves the tenant-scoped database context, reads your credentials from your database only, and establishes the connection. Credentials never appear in Docker images, source control, environment variables, or any shared configuration. This means even in a multi-tenant deployment, one customer’s credentials are physically inaccessible to another customer’s application context.
Each customer’s database has independent backup schedules with point-in-time recovery — typically a 15-minute RPO (Recovery Point Objective) using cloud-managed database services. The application tier is fully stateless, which means it recovers instantly via Kubernetes pod rescheduling with no data loss. Redis cache is ephemeral by design — if lost, it causes a brief performance dip while the cache warms, but no business data is affected. In multi-tenant deployments, the tenant registry (the routing layer that maps requests to databases) is the highest-priority component and is replicated with the strongest durability guarantees. For organizations requiring geographic redundancy, cross-region disaster recovery is supported through cloud-managed database replication and multi-region Kubernetes deployment.
Yes — full white-labeling is built into the platform. The theme editor in the Remix frontend allows per-tenant customization of colors, fonts, logos, and layout through Tailwind CSS variables stored in the database. Embedded payment forms automatically inherit the tenant’s theme so they feel native within ERP interfaces. Email notifications and customer-facing communications use per-tenant Handlebars templates with your branding. The result is a seamless chain: your team sees your brand in the admin portal, and your end-customers see your brand on payment pages, invoices, and email receipts — with no trace of the underlying platform.