← Back to tutorials

Cloud Transport Management on BTP: move an app from DEV to TEST and PRD

Set up cTMS as the cloud's STMS: destinations, nodes, routes and a step-by-step release of an MTA app, with the typical errors and how to fix them.

También disponible en español →

If you come from ABAP, you know the ritual: release the transport request, it lands in the QA queue, someone imports it, it gets tested, then it moves to production. On SAP BTP that role belongs to Cloud Transport Management (cTMS): you model environments as nodes, connect them with routes, and every version of your app travels DEV → TEST → PRD through controlled imports.

STMS (ABAP) cTMS
Create the transport request Upload a file (creates the transport request)
Objects in the request The app’s .mtar file
Release the request Upload it to the DEV node
QAS import queue TEST node queue
Import into QAS / PRD Manual Import in TEST / PRD

Key difference: each .mtar is a full deployment of the app, not a delta. The new version replaces the previous one.

In this tutorial we transport a simple Fiori app packaged as an MTA (Multi-Target Application).

The architecture

Global account
├── "Central Service" subaccount   → cTMS (nodes, routes, destinations)
└── Runtime subaccount             → Cloud Foundry
                                      ├── space DEV
                                      ├── space TEST
                                      └── space PRD
  • cTMS lives in its own subaccount, separate from the environments. That is the pattern SAP recommends: you control who can transport without granting access to the environments.
  • On a trial account the three environments are spaces in one subaccount, because new subaccounts usually have no memory available. In a real landscape each environment would normally be a separate subaccount; the rest of the tutorial stays the same.

1. Set up cTMS

In the central subaccount:

  1. Entitlements: add both Cloud Transport Management plans: lite (the user interface) and standard (API access). On trial they come assigned to the trial subaccount: remove them there so you can assign them to the central one.
  2. Subscription: in the Service Marketplace, subscribe to Cloud Transport Management with the lite plan.
  3. Roles: create a role collection (for example, TMS Admin), add the subscription’s Administrator role template to it and assign yourself. For people who only import there is the Import Operator template.
  4. Check: open the application from Instances and Subscriptions. You should see an empty Overview page.

2. Prepare the target environments

Before the first transport, every target must have all the services your mta.yaml requires. For this tutorial’s app:

Service Plan Purpose
Cloud Foundry Runtime MEMORY Run the approuter (256 MB per environment)
Authorization and Trust Management (xsuaa) application App login
HTML5 Application Repository app-host Store the app content
HTML5 Application Repository app-runtime Serve it from the router
Destination Service lite The app’s destinations

Check the org’s real memory with cf org-quota <quota>: the cockpit may show the entitlement as assigned while the org still has 0 MB.

3. Destinations: where each node deploys

In the central subaccount, Connectivity → Destinations, create one per environment. They all point to the Cloud Foundry deploy service:

https://deploy-service.cf.<region>.hana.ondemand.com/slprot/<org>/<space>/slp
Field Value
Name TMS_DEV, TMS_TEST, TMS_PRD
Type HTTP
Proxy Type Internet
Authentication BasicAuthentication
User / Password A technical user with the Space Developer role in the target space

Three warnings that save hours:

  • Org and space are case-sensitive. dev instead of DEV causes a Not Found error on import.
  • “Check Connection” does not validate credentials, nor whether the org or space exist: only that the URL answers. The real test is the first import, or a cf login with the same user.
  • Make sure each destination points to its own environment. An import can end as Succeeded and still have deployed to the wrong place: cTMS deploys wherever the destination says.

4. Nodes and routes

In the cTMS application, Transport Nodes:

Node Allow Upload Forward Mode Content Type Destination
DEV ✅ Pre-Import Multi-Target Application TMS_DEV
TEST ❌ On Success Multi-Target Application TMS_TEST
PRD ❌ On Success Multi-Target Application TMS_PRD

Leave automatic import turned off on all three: every import will be manual and controlled.

And in Transport Routes: DEV_TO_TEST (DEV → TEST) and TEST_TO_PRD (TEST → PRD).

Forward modes

Mode When the version moves to the next node
Pre-Import When the import starts in the current node (not on upload)
Post-Import After the import, whether it succeeded or not
On Success Only if the import succeeded
Manual When someone forwards it from the queue

With this setup, a version reaches TEST as soon as you import it into DEV, and reaches PRD only if the TEST import succeeded.

5. The application: three MTA details

Any MTA works. If you use a Fiori app with its own approuter, watch these three points.

The version, on every release. cTMS identifies each transport by its file; always bump it:

_schema-version: "3.2"
ID: helloworld-mta
version: 0.0.2

A different xsappname per space. If the same app lives in several spaces of one subaccount, its XSUAA instances would clash. The ${space} variable prevents it:

  - name: helloworld-mta-uaa
    type: org.cloudfoundry.managed-service
    parameters:
      config:
        tenant-mode: dedicated
        xsappname: helloworld-mta-${space}
      path: ./xs-security.json
      service: xsuaa
      service-plan: application

The redirect-uris in xs-security.json. Without them, XSUAA rejects the router’s login with OpenID provider cannot process the request:

{
  "xsappname": "helloworld-mta",
  "tenant-mode": "dedicated",
  "scopes": [],
  "role-templates": [],
  "oauth2-configuration": {
    "redirect-uris": ["https://*.cfapps.<region>.hana.ondemand.com/**"]
  }
}

oauth2-configuration goes inside the root object, as just another property.

6. The release, step by step

  1. Build and test the app (in SAP Business Application Studio, with the preview).

  2. Bump version in mta.yaml.

  3. Build the archive from the MTA folder:

    mbt build
  4. Download the .mtar from mta_archives/.

  5. In cTMS: Transport Nodes → DEV → Upload. Pick the .mtar and write a useful description (version and requirement).

  6. In the DEV queue, Import Selected: it deploys to DEV and, thanks to Pre-Import, moves to the TEST queue.

  7. Validate the app in DEV.

  8. In the TEST queue, Import Selected. If it succeeds, it moves to the PRD queue (On Success).

  9. Validate in TEST.

  10. Once approved, Import Selected in the PRD queue.

Two queue actions worth telling apart: Reset lets you re-import a version already processed in that node; Remove takes it out of the queue to discard it.

7. Typical errors

Symptom Cause Fix
Cannot create the node without a destination A node with a Content Type (non-virtual) requires one Create the destination before the node
Uploaded to DEV, nothing shows in TEST Pre-Import forwards on import, not on upload Import into DEV
Error during client creation: Unauthorized Wrong password in the destination Fix it; use a technical user
Error during client creation: Not Found Org or space misspelled in the URL Copy the exact names, case included
Service plan application not found Missing XSUAA entitlement in the target Assign xsuaa – application to that subaccount
Router Stopped, 0 MB available The org quota did not sync with the entitlements Check cf org-quota; on trial, use the trial subaccount’s org, which does have memory
Login: OpenID provider cannot process the request redirect-uris missing in xs-security.json Add them, bump the version and transport again
Import Succeeded but the app is in another environment The destination points to the wrong environment Fix the URL, Reset the transport and re-import. Clean up whatever was deployed by mistake

On a trial account, Cloud Foundry stops apps once a day. If your app does not answer, cf start <app>.

8. Change rules

The tool is half of it; the other half is the process:

  • Nobody imports into production outside the defined route.
  • Whoever develops a change does not approve or import it.
  • Every change that reaches PRD has a requirement, approved tests and an associated transport.
  • Destinations use technical users, never personal ones.

Every change in production should be able to answer three questions: who asked for it, who tested it and who approved it.

Next step

The same cTMS transports other kinds of content. Integration Suite iFlows, for example, travel per package: transports are enabled in the Integration Suite settings, the Content Agent packages the content, and the nodes’ destinations point to the target Cloud Integration tenant. For an iFlow to adapt to each environment without editing it, start by externalizing its parameters.