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: 
Former Member

One key ingredient of SAP CAP is it's openness. Openness especially means, that we are free to choose the development tools, the used database, the libraries, etc. Especially we are free to choose on which platform we run and operate CAP. All we need is @Sap/cds-dk and node.js.

This article demonstrates:

  1. How to deploy a CAP App to Heroku, a popular PaaS which supports direct deployment from a git repository, and

  2. How to bundle a CAP App into a Docker container which provides even more flexibility to deploy on any docker supported platform

Sample Project

For this article I reuse my sample project "Yet Another Covid-19 Tracker" which I described recently in the article SAP CAP Remote Services & SAP Fiori Elements.

But of course you can follow this article as well with your own project or a sample cap project from the SAP Github Samples.

Prepare CAP for Production

While development SAP CAP comes with several Features activated by default to ease rapid development. These include for example an in-memory db, mocked authentication, Fiori Preview, live reload or mocked bindings. In production we usually do not want to lean back on default Features meant for development, but want to make Features explicit.

We can easily check which Features are activated by running cds env. In package.json or .cdsrc.json we can explicitly override the default setting, if we want to. Find more about environment variables in the official SAP CAP for node.js documentation.

The default cds environment variables are set according to the current NODE_ENV variable. NODE_ENV is usually set to production in productive environments and something else, e.g., development, in other environments. If set to production the development features are deactivated. This may cause problems and errors if we rely on these features, e.g., a missing service binding.

In the following table you can compare the difference between development and productive settings of a clean CAP project as of June 2021:

Parameter development production
_sources [.env, default-env.json, .cdsrc.json, defaults.js, process.env] [default-env.json, .cdsrc.json, defaults.js, process.env]
env  development
features.fiori_preview  true  false
features.fiori_routes  true  false
features.in_memory_db  true  false
features.live_reload  true  false
features.mocked_bindings  true  false
profiles  [ 'development' ]  [ 'production' ]
requires.auth.kind  mocked-auth  JWT-auth
requires.auth.strategy  mock  JWT
requires.auth.users.*  true
requires.auth.users.alice.roles  [ 'admin' ]
requires.auth.users.bob.roles  [ 'builder' ]
requires.sql.credentials.database  :memory:
requires.sql.kind  sqlite  hana
requires.sql.use  sqlite  hana

Configuring / Activating CDS Features

For my project I would like to use the in-memory DB Feature. Therefore, I simply add the following configuration into .cdsrc.json:
"features": {
"in_memory_db": true

Test CAP Productive Setup

The different behavior of CAP in development and production requires us to test any CAP application (or node.js application in general) before deploying into production. We can do this by simulating a productive environment by first setting NODE_ENV to production.
# windows powershell

# windows cmd
set NODE_ENV=production

# unix
export NODE_ENV=production

Next we simulate typical steps a deployment executes by running the following commands:
# clean install of production dependencies
npm ci --only=production

# start cap app
npm run start

As the NODE_ENV variable is set to production the commands behave differently and remove dev dependencies and the cds commands included in the start script use the productive settings as well.

Warning: Be aware of the fact, that you may have installed @Sap/cds-dk globally, which contains commands which are not available in a productive environment. If you rely on those commands you may need to add the package to your dependencies, or better rethink to not rely on the command(s) at all.

Environment specific variables

Another typical pitfall is to forget setting the environment variables in the target environment. While development we typically use configuration files like .env or default-env.json to set those variables. But they are usually not checked in into the code repository because they are not only environment specific but may contain sensitive information such as passwords or API keys.

Therefore, we need to check if we have set all environment variables in the target environment before deployment.

Note: Based on the environment variables, .env files are not evaluated in production.

Configuring Log Levels

In a productive environment we usually don't want to log every http request we serve. Therefore, we can set the log level for the module cds to warn or error for examplein .cdsrc.json:
"log": {
"levels": {
"cds": "warn"

Deploy CAP to Heroku

One popular Platforms (PaaS) to deploy and run projects in the cloud is Heroku. Heroku is especially handy for simple POCs or building MVPs as it is very simple and straight forward. You can directly deploy from your git repository to Heroku.

Configure environment variables

After we created a new project we need to configure all environment variables which are only included in environment specific files and therefore not part of the deployment. One typical variable could be the destinations variable, which contains name, url, user and password of a service which we want to integrate.

Deploy git repository

Deployment is as easy as clicking a button after connecting your git repository with heroku. Alternatively, you can also listen on changes on a specific branch and deploy whenever a new commit occurs.

Deploy Anywhere with Docker

Deploying to Heroku is straight forward. But we can do it even more generic and containerize the application with docker.

Therefore, we create a Dockerfile in the root folder of the project:
FROM node:14-alpine

# use productive environment
ENV NODE_ENV production

# copy source as node user
WORKDIR /usr/src/app
COPY --chown=node:node . .

# install dependencies
RUN npm ci --only=production

# run app as node user
USER node
CMD ["npm", "start"]

Then we can run the following command to build the docker file:
docker build -t <YOUR_CONTAINER_NAME> .

This docker container can now be deployed anywhere. You can test it locally as follows:
docker run -p 4004:4004 -t <YOUR_CONTAINER_NAME>

If something does not work and you want to inspect the container you can open a shell in the container like this:
docker run -i -t <YOUR_CONTAINER_NAME> /bin/sh

Final Thoughts

You see that it is quite simple to use and deploy SAP CAP anywhere. Staying in the SAP ecosystem and using SAP's services eases developing enterprise grade applications, but it is not mandatory.

My application uses an in-memory DB for caching purposes only. If you want to use a persistent DB but do not want to use HANA, then you should give cds-pg a try, which is an adapter for PostgreSQL.

If you want to try out the app, you can find it here: