Feature Toggles
Toggled features are pre-built extensions built by the provider of a SaaS application, which can be switched on selectively per subscriber.
This guide is available for Node.js and Java.
Use the toggle in the title bar or press v to switch.
Introduction and Overview
CAP feature-toggled aspects allow SaaS providers to create pre-built features as CDS models, extending the base models with new fields, entities, as well as annotations for SAP Fiori UIs. These features can be assigned to individual SaaS customers (tenants), users, and requests and are then activated dynamically at runtime, as illustrated in the following figure.
Get cloud-cap-samples-java for step-by-step Exercises
The following steps will extend the CAP samples for Java app to demonstrate how features can extend data models, services, as well as SAP Fiori UIs. If you want to exercise these steps, get cloud-cap-samples-java before, and prepare to extend the Fiori app:
git clone https://github.com/SAP-samples/cloud-cap-samples-java
cd cloud-cap-samples-java
mvn clean installNow, open the app in your editor, for example, for VS Code type:
code .Get cap/samples for Step-By-Step Exercises
The following steps will extend the cap/samples/bookstore app to demonstrate how features can extend data models, services, as well as SAP Fiori UIs. If you want to exercise these steps, get cap/samples before, and prepare to extend the bookstore app:
git clone https://github.com/capire/samples samples
cd samples
npm installNow, open the bookstore app in your editor, for example, by this if you're using VS Code on macOS:
code bookstoreEnable Feature Toggles
Add @sap/cds-mtxs Package Dependency
For example, like this:
npm add @sap/cds-mtxsSwitch on cds.requires.toggles
Switch on feature toggle support by adding cds.requires.toggles: true.
Adding Features in CDS
Add a subfolder per feature to folder fts and put .cds files into it. The name of the folder is the name you later on use in feature toggles to switch the feature on/off. In our samples app, we add two features isbn and reviews as depicted in the following screenshot:

The name of the .cds files within the fts/ subfolders can be freely chosen. All .cds files found in there will be served, with special handling for index.cds files, as usual.
Feature fts/isbn
Create a file fiori/fts/isbn/schema.cds with this content:
using { CatalogService, sap.capire.bookshop.Books }
from '../../app/browse/fiori-service';
// Add new field `isbn` to Books
extend Books with {
isbn : String @title:'ISBN';
}
// Display that new field in list on Fiori UI
annotate CatalogService.Books with @(
UI.LineItem: [... up to {Value:author}, {Value:isbn}, ...]
);This feature adds a new field isbn to entity Books and extends corresponding SAP Fiori annotations to display this field in the Browse Books list view.
TIP
Note that all features will be deployed to each tenant database in order to allow toggling per user/request.
Feature fts/reviews
Create a file fiori/fts/reviews/schema.cds with this content:
using { CatalogService } from '../../app/browse/fiori-service';
// Display existing field `rating` in list on Fiori UI
annotate CatalogService.Books with @(
UI.LineItem: [... up to {Value:author}, {Value:rating}, ...]
);This feature extends corresponding SAP Fiori annotations to display already existing field rating in the Browse Books list view.
Limitations
WARNING
Note the following limitations for .cds files in features:
- no
.cdsfiles in subfolders, for example,fts/isbn/sub/file.cds - no
usingdependencies between features, any entity, service or type that you refer to or extend needs to be part of the base model - further limitations re
extend aspect→ to be documented
Toggling Features
In principle, features can be toggled per request, per user, or per tenant; most commonly they'll be toggled per tenant, as demonstrated in the following.
In Development
CAP Node.js' mocked-auth strategy has built-in support for toggling features per tenant, per user, or per request. To demonstrate toggling features per tenant, or user, you can add these lines of configuration to our package.json of the SAP Fiori app:
{"cds":{
"requires": {
"auth": {
"users": {
"carol": { "tenant": "t1" },
"erin": { "tenant": "t2" },
"fred": { "tenant": "t2", "features":[] }
},
"tenants": {
"t1": { "features": ["isbn"] },
"t2": { "features": "*" }
}
}
}
}}CAP Java's Mock User Authentication with Spring Boot allows to assign feature toggles to users based on the mock user configuration. To demonstrate toggling features per user, you can add these lines to the mock user configuration in the srv/src/main/resources/application.yaml file:
cds:
security.mock.users:
- name: carol
features:
- isbn
- name: erin
features:
- isbn
- reviews
- name: fred
features:In effect of this, for the user carol the feature isbn is enabled, for erin, the features isbn and reviews are enabled, and for the user fred all features are disabled.
In Production
No features toggling for production yet
Note that the previous sample is only for demonstration purposes. As user and tenant management is outside of CAP's scope, there's no out-of-the-box feature toggles provider for production yet. → Learn more about that in the following section Feature Vector Providers.
For productive use, the mock user configuration must not be used. The set of active features is determined per request by the Feature Toggles Info Provider.
You can register a Custom Implementation as a Spring bean that computes the active feature set based on the request's UserInfo and ParameterInfo.
Test-Drive Locally
To test feature toggles, just run your CAP server as usual, then log on with different users, assigned to different tenants, to see the effects.
Run cds watch
Start the CAP server with cds watch as usual:
cds watch→ in the log output, note the line reporting:
[cds] - serving cds.xt.ModelProviderService {
path: '/-/cds/model-provider',
impl: '@sap/cds/srv/model-provider.js'
}The
ModelProviderServiceis used by the runtime to get feature-enhanced models.
See Effects in SAP Fiori UIs
To see the effects in the UIs open three anonymous browser windows, one for each user to log in, and:
- Open SAP Fiori app in browser and go to Browse Books.
- Log in as
caroland seeISBNcolumn in list. - Log in as
erinand seeRatingsandISBNcolumns in list. - Log in as
fredand no features for Fred, even though same tenant as Erin.
For example the displayed UI should look like that for erin:

Model Provider in Sidecar
The ModelProviderService, which is used for toggling features, is implemented in Node.js only. To use it with CAP Java apps, you run it in a so-called MTX sidecar. For a CAP Node.js project, this service is always run embedded with the main application.
Create Sidecar as Node.js Project
An MTX sidecar is a standard, yet minimalistic Node.js CAP project. By default it's added to a subfolder mtx/sidecar within your main project, containing just a package.json file:
{
"name": "mtx-sidecar", "version": "0.0.0",
"dependencies": {
"@sap/cds": "^9",
"@sap/cds-mtxs": "^3",
"express": "^4"
},
"cds": {
"profile": "mtx-sidecar"
}
}{
"name": "mtx-sidecar", "version": "0.0.0",
"dependencies": {
"@sap/cds": "^9",
"@sap/cds-mtxs": "^3",
"express": "^4"
},
"cds": {
"profiles": [
"mtx-sidecar",
"java"
]
}
}Learn more about setting up MTX sidecars.
Add Remote Service Link to Sidecar
TIP
In Node.js apps you usually don't consume services from the sidecar. The ModelProviderService is served both, embedded in the main app as well as in the sidecar. The following is documented for the sake of completeness only...
You can use the from-sidecar preset to tell the CAP runtime to use the remote model provider from the sidecar:
"cds":{
"requires": {
"toggles": true,
"cds.xt.ModelProviderService": "from-sidecar"
}
}You need to configure the CAP Java application to request the CDS model from the Model Provider Service. This is done in the application.yaml file of your application. To enable the Model Provider Service for local development, add the following configuration to the default profile:
cds:
model:
provider:
url: http://localhost:4005
# remove, in case you need tenant extensibility
extensibility: falseTest-Drive Sidecar Locally
With the setup as described in place, you can run the main app locally with the Model Provider as sidecar. Simply start the main app and the sidecar in two separate shells:
First, start the sidecar as the main app now depends on the sidecar:
cds watch mtx/sidecarThen, start the main app in the second shell:
cds watchmvn spring-boot:runRemote getCsn() Calls to Sidecar at Runtime
When you now run and use our application again as described in the previous section See Effects in SAP Fiori UIs, you can see in the trace logs that the main app sends getCsn requests to the sidecar, which in response to that reads and returns the main app's models. That means, the models from two levels up the folder hierarchy as configured by root: ../.. for development.
See Effects in SAP Fiori UIs
To see the effects in the UIs open three anonymous browser windows, one for each user to log in, and:
- Open SAP Fiori app in browser and go to Browse Books.
- Log in as
caroland seeISBNcolumn in list. - Log in as
erinand seeRatingsandISBNcolumns in list. - Log in as
fredand no features for Fred, even though same tenant as Erin.
For example the displayed UI should look like that for erin:

Feature Vector Providers
In principle, features can be toggled per request using the req.features property (req being the standard HTTP req object here, not the CAP runtimes req object). This property is expected to contain one of the following:
- An array with feature names, for example,
['isbn','reviews']. - A string with comma-separated feature names, for example,
'isbn,reviews'. - An object with keys being feature names, for example,
{isbn:true,reviews:true}.
So, to add support for a specific feature toggles management you can add a simple Express.js middleware as follows, for example, in your server.js:
const cds = require ('@sap/cds')
cds.on('bootstrap', app => app.use ((req,res,next) => {
req.features = req.headers.features || 'isbn'
next()
}))Feature-Toggled Custom Logic
Evaluate the FeatureTogglesInfo in custom code to check if a feature is enabled:
@Autowired FeatureTogglesInfo features;
...
if (features.isEnabled("discount")) {
// specific coding when feature 'discount' is enabled...
}Within your service implementations, you can react on feature toggles by inspecting cds.context.features like so:
const { features } = cds.context
if ('isbn' in features) {
// specific coding when feature 'isbn' is enabled...
}
if ('reviews' in features) {
// specific coding when feature 'reviews' is enabled...
}
// common coding...Or alternatively:
const { isbn, reviews } = cds.context.features
if (isbn) {
// specific coding when feature 'isbn' is enabled...
}
if (reviews) {
// specific coding when feature 'reviews' is enabled...
}
// common coding...