Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
Showing results for 
Search instead for 
Did you mean: 
This example demonstrates how to build multitenant application using Cloud Application Programming Model Java SDK and mtx-sidecar node module.


This sample application contains

  • UI module containing a public welcome page which contains link to fetch data from its own tenant database.

  • backend module which contains CDS service exposing OData CRUD APIs on Books entity

  • Database (db) module which contains schema.cds to create books table

  • Node.js based mtx-sidecar module used to handle tenant provisioning

What is Multitenancy?

SAP BTP provides a multitenant functionality that allows application providers to own, deploy, and operate tenant-aware applications for multiple consumers, with reduced costs.

With tenant-aware applications, you can:

  1. Separate data securely for each tenant

  2. Save resources by sharing them among tenants

  3. Update applications efficiently in a single step

Configuring the Approuter, required services and mtx-sidecar module:

To enable multitenancy on the SAP BTP, we need to deploy tenant aware approuter, mtx-sidecar module and configure below three services.

Only when these services are bound to your application, the multitenancy feature is turned on.

  1. XSUAA

  2. Service Manager

  3. SaaS Provisioning service (saas-registry)

Approuter module:

You deploy the approuter application as a Cloud Foundry application and as a logical part of the multitenant application. Then you configure approuter application as an external access point of the application.

Each multitenant application has to deploy its own application router and the application router handles requests of all tenants to the application.

The application router must determine the tenant-specific subdomain. This determination is done by using a regular expression defined in the environment variable TENANT_HOST_PATTERN. The application router then forwards the authentication request to the tenant User Account and Authentication (UAA) service and the related identity zone.

If you have multiple routes to the same application, for example:
tenant1.<application domain> and tenant2.<application domain>


TENANT_HOST_PATTERN: "^(.*)-<application domain>"




Bind your multitenant application and the approuter application to the SAP Authorization and Trust Management service (technical name: xsuaa) instance, which acts as an OAuth 2.0 client to your application.

In multi-tenant environments, tenants subscribe to and consume applications, which are registered as clients at the XS UAA. XS UAA creates a new OAuth2 client per application for each tenant. The shared tenant mode is mandatory for an application router configured for multi-tenancy applications. Also, a special configuration of an XS UAA service instance is required to enable authorization between the SaaS Provisioning service, Cloud Application Programming Model Java application, and MTX sidecar.

The service can be configured in the mta.yaml by adding an xsuaa resource as follows:
-  name: <xsuaa instance name>
service-plan: broker
path: ./security.json
xsappname: <appname>

Choose a value for property xsappname that is unique globally.

An example security.json file looks like this:
"xsappname": <appname>,
"tenant-mode": "shared",
"scopes": [
"name": "$XSAPPNAME.mtcallback",
"description": "Multi Tenancy Callback Access",
"grant-as-authority-to-apps": [
"$XSAPPNAME(application, sap-provisioning, tenant-onboarding)"
"name": "$XSAPPNAME.mtdeployment",
"description": "Scope to trigger a re-deployment of the database artifacts"
"authorities": [

The mtcallback scope is required by the onboarding process. The mtdeployment scope is required to redeploy database artifacts at runtime.

Service Manager:

A service-manager instance is required that the Cloud Application Programming Model Java SDK can create database containers per tenant at application runtime. It doesn’t require special parameters and can be added as a resource in mta.yaml as follows:
-  name: service-manager
type: org.cloudfoundry.managed-service
service: service-manager
service-plan: container

SaaS Provisioning Service (saas-registry):

A saas-registry service instance is required to make your application known to the SAP BTP Provisioning service and to register the endpoints that should be called when tenants are added or removed. The service can be configured as a resource in mta.yaml as follows
- name: saas-registry
type: org.cloudfoundry.managed-service
service: saas-registry
service-plan: application
appName: <app display name> # this is the text on the tile
xsappname: <appname> # this is the value from xsuaa.parameters.config.xsappname
getDependencies: ~{srv/url}/mt/v1.0/subscriptions/dependencies
onSubscription: ~{srv/url}/mt/v1.0/subscriptions/tenants/{tenantId}
- name: srv

  • appName: Choose an appropriate application display name.

  • xsappname: Use the value for xsappname you configured at your UAA service instance.

  • appUrls: Configure the callback URLs used by the SaaS Provisioning service to get the dependencies of the application and to trigger a subscription. In the above example, the property ~{srv/url} that is provided by the srv module is used.

mtx-sidecar module:

Cloud Application Programming Model provides the npm module for Node.js published as @Sap/cds-mtx on It provides APIs for implementing SaaS applications on SAP BTP. Java applications need to run and maintain the cds-mtx module as a sidecar application. Multitenant Cloud Application Programming Model Java applications automatically expose the tenant provisioning APIs.

provisioning: implements the subscription callback API as required by SAP BTP. If a tenant is subscribing to the SaaS application, the onboarding request is handled. cds-mtx is contacting the SAP HANA Service Manager service to create a new HDI container for the tenant. Then, database artifacts get deployed into this HDI container. In addition, the unsubscribe operation and the "get dependencies" operations are supported.

This section describes how to use the cds-mtx Node.js module and add the MTX sidecar microservice to the mta.yaml file.

In a dedicated project subfolder named mtx-sidecar, create a Node.js start script in a file named server.js to bootstrap the cds-mtx library:
const app = require('express')();
const cds = require('@sap/cds');

const main = async () => {
const PORT = process.env.PORT || 4004;
const scope = process.env.CDS_MULTITENANCY_SECURITY_SUBSCRIPTIONSCOPE || 'mtcallback';

const provisioning = await'ProvisioningService');
provisioning.before(['UPDATE', 'DELETE', 'READ'], 'tenant', async (req) => {
// Check for the scope of the SaaS Provisioning Service
if (! {
// Reject request
const e = new Error('Forbidden');
e.code = 403;
return req.reject(e);



To define the dependencies and start command, also create a file package.json like this:
"name": "deploy",
"dependencies": {
"@sap/cds": "^5.0.4",
"@sap/cds-mtx": "^1.2.0",
"@sap/hdi-deploy": "^4.0.4",
"@sap/instance-manager": "^2.2.0",
"@sap/xssec": "^3",
"@sap/hana-client": "^2.8.16",
"express": "^4.17.1",
"passport": "^0.4.1"
"scripts": {
"start": "node server.js"

Because the MTX sidecar will build the CDS model, you need to configure the build by means of two .cdsrc.json files:

The first .cdsrc.json file goes into the root folder of your project and specifies from which location the CDS files should be collected. The following example demonstrates this:
"build": {
"target": ".",
"tasks": [
"for": "java-cf"
"for": "mtx",
"src": ".",
"dest": "mtx-sidecar"
"for": "hana"
"hana": {
"deploy-format": "hdbtable"
"sql": {
"dialect": "plain"

The second .cdsrc.json file goes into the mtx-sidecar directory. This could look, for example, like:
"hana": {
"deploy-format": "hdbtable"
"build": {
"tasks": [
"for": "hana",
"src": "db",
"options": {
"model": [
"for": "java-cf",
"src": "srv",
"options": {
"model": [
"odata": {
"version": "v4"
"requires": {
"db": {
"kind": "hana",
"multiTenant": true,
"vcap": {
"label": "service-manager"
"uaa": {
"kind": "xsuaa"

Now, add the mtx-sidecar module to your mta.yaml file:
# --------------------- SIDECAR MODULE -----------------------
- name: mtx-sidecar
# ------------------------------------------------------------
type: nodejs
path: mtx-sidecar
memory: 256M
disk-quota: 512M
- name: xsuaa
- name: service-manager
- name: sidecar
url: ${default-url}

The mtx-sidecar module requires the XS UAA and Service Manager services. Also you need to provide its URL to be able to configure the URL in the service module

Wiring It Up:

To bind the previously mentioned services and the MTX sidecar to your Cloud Application Programming Model Java application, you could use the following example of the srv module in the mta.yaml file:
# --------------------- SERVER MODULE ------------------------
- name: multitenantapp-srv
# ------------------------------------------------------------
type: java
path: srv
memory: 1024M
disk-quota: 256M
buildpack: sap_java_buildpack
builder: custom
- mvn clean package -DskipTests=true
build-result: target/*-exec.jar
- name: service-manager
- name: xsuaa
- name: saas-registry
- name: sidecar
- name: app
- name: srv
url: '${default-url}'

Deploy to SAP Business Technology Platform:

Please follow below steps to deploy to SAP BTP (Cloud Foundry) Trial landscape.

  • Create an SAP HANA Cloud Instance in your SAP Business Technology Platform space.

Please follow below screenshots to create an instance and in step 3, please select allow all IP addresses as shown in the screenshot. You can select all default values and click on create. This will take few minutes.

Create SAP HANA Cloud Instance:

Screenshot 1:

Create HANA Cloud Instance

Screenshot 2:


Note: once the SAP HANA Cloud instance is created, please copy the instance id and replace the value in as follows.
@Before(event = MtSubscriptionService.EVENT_SUBSCRIBE)
public void beforeSubscription(MtSubscribeEventContext context) {
new InstanceCreationOptions().withProvisioningParameters(
Collections.singletonMap("database_id", <<INSTANCE ID>>)));

  • Run mbt build

  • Run cf login

  • Run cf deploy mta_archives/multitenantapp_1.0.0-SNAPSHOT.mtar

Sample Demo:

Once the deployment is successful, you should see all the 4 apps in started status as below.

Apps Deployed

Create a new SubAccount to onboard a new tenant as shown below.

SubAccount creation

Subscribe to the Multi Tenant App as below.

Subscribe to application

Subscription Success

Go to application and you will see route does not exists error as below.

Go To Application

Route does not exists

Add tenant url as a new application route and map tenant URL to AppRouter URL as shown below.

Add Route

Map Route

Access the application using the newly created tenant URL and this should display a welcome page as below. Click on Get My Tenant Data link and should authenticate the user against SAP Default IDP (enabled by default) and should show all Book entries from the tenant database as below.


Books Listing no data

Add a new book entry to tenant database and check the same using Get My Tenant Data link as shown below.

First we need to request for CSRF token.

Get CSRF Token

Post a book entry.

Post book entry

Refresh the page and check if data is retrieved.

Books Listing with data



In this blog, I have tried to demonstrate how to build multitenant application using Cloud Application Programming Model Java SDK and cds-mtx node module. You can find working example at

Please note that, I have developed and tested this example using SAP Business Application Studio and SAP BTP Trial landscape.

Links and Further Reading:

Capire >> Multitenancy

SAP Business Technology Platform >> Development >> Development in the Cloud Foundry Environment >> D...

Cloud Application Programming Model Samples for Java

SAP HANA Academy >> SAP BTP Multitenant Business Applications


How to obtain support/help:

Please provide your feedback, thoughts in the comments section.