Multitenancy
Introducing the fundamental concepts of multitenancy, underpinning SaaS solutions in CAP. It describes how to run and test apps in multitenancy mode with minimized setup and overhead.
Introduction & Overview
CAP has built-in support for multitenancy with the @sap/cds-mtxs
package.
Essentially, multitenancy is the ability to serve multiple tenants through single clusters of micro service instances, while ensuring strict isolation with respect to tenants’ data and access to it. Tenants are clients using SaaS solutions.
In contrast to single-tenant mode, applications aren’t serving end-user request immediately after deployment, but wait for tenants to subscribe.
Enable Multitenancy
The easiest way to enable multitenancy is to execute this in your project root:
cds add multitenancy
Essentially, this automates the following two steps.
1. Add @sap/cds-mtxs
Package Dependency
npm add @sap/cds-mtxs
2. Switch on cds.requires.multitenancy
Add the following configuration, for example, to your package.json
:
"cds": {
"requires": {
"multitenancy": true
}
}
In essence, this configuration option tells the CAP Node.js runtime to run in multitenancy mode. In particular, this means using tenant-specific database connection pools.
Test-Drive Locally
In order to test multitenancy, just run your CAP server as usual, then log on with different users, assigned to different tenants, to see the effects.
Start Server with cds watch
as Usual
cds watch
This produces an output like that:
In contrast to single-tenant mode, we recognize differences in the log output with regards to the database initialization and the services that are bootstrapped.
Deferred Database Initialization
Tenant-specific databases are initialized on tenant subscriptions only.
We can recognize that from the log output. The in-memory database init messages are missing, which would show up in single-tenant mode:
MTX Services Bootstrapped
These MTX services are served in addition to our application services:
cds.xt.ModelProviderService
cds.xt.DeploymentService
cds.xt.SaasProvisioningService
Learn more about these services in MTX Services Reference
In essence, the started server is now waiting for tenant subscriptions. Note: No end-user requests can be served yet.
Subscribing Tenants
Upon tenant subscriptions required tenant-specific resources need to be created and initialized, most prominently the tenants’ databases.
Send subscribe
Events
Now, let’s subscribe one tenant t1
by sending a subscribe
event to the DeploymentService
using any REST Client plugin in VSCode:
POST http://localhost:4004/-/cds/deployment/subscribe HTTP/1.1
Content-Type: application/json
Authorization: Basic yves:
{ "tenant": "t1" }
Bootstrapping Tenant-Specific Databases
In response to each subscribe
request, the server deploys and bootstraps a new isolated in-memory database for each, tenant t1
, and tenant t2
, which can be seen from respective log outputs:
Upgrading Tenants
Later on when our app is enhanced, we can upgrade subscribed tenants. Use the upgrade
request that is very similar to the subscribe requests before.
Send upgrade
Events
POST http://localhost:4004/-/cds/deployment/upgrade HTTP/1.1
Content-Type: application/json
Authorization: Basic yves:
{ "tenant": "t1" }
In response to upgrade
request, the DeploymentService reads the latest models and content from the latest deployed version of the application and redeploys that to the respective tenant’s database.
Serving Tenants
Now, as we have our tenant-specific databases deployed and filled, our server can serve tenant-specific end-user requests. In our nutshell setup we can demonstrate this as follows:
Use the App with Different Users/Tenants
- Open a new anonymous browser window.
- Open http://localhost:4004/vue/index.html in it.
- Log in as
carol
.
— a pre-defined user in tenantt1
in the built-inmocked
auth strategy - List of Books is displayed with user + tenant information at the top.
Repeat these steps, this time login in with erin
another pre-defined user in tenant t2
.
Tenant Isolation
As we can see also from the server’s log output, in multitenant mode, all end-user requests happen within the context of a specific tenant, which the individual users are assigned to:
The CAP runtimes guarantee, that each request is served in isolation, which means all work on separate app data, both in service layers as well as in databases.
You can validate this, for example by ordering a few books in the carol
window, then ordering some other books in the erin
window and see that both have independent data.
Authentication and Tenants
How users are assigned to tenants and how tenants are determined at runtime largely depends on your identity providers and authentication strategies. The mocked
authentication strategy, used by default with cds watch
, has some pre-defined users configured via cds env
defaults. You can inspect these by running cds env get requires.auth
:
You can also add or override users or tenants by adding something like this to your package.json
:
"cds":{
"requires": {
"auth": {
"users": {
"u2": { "tenant": "t2" },
"u3": { "tenant": "t3" }
}
}
}
}
MTX Services Reference
See Reference docs for MTX Services to learn more about the detailed service and configuration options, in particular also about setting up MTX sidecars.
Extending and Customizing SaaS Solutions
See our new guide for Extending and Customizing SaaS Solutions.
Old MTX Reference
See Reference docs for former, ‘old’ MTX Services.