The MTA: your deployment contract
CAP projects deploy to BTP as MTAs (Multi-Target Applications): one archive containing your database deployer, backend services, approuter, and UI — with all service bindings declared. Understand the mta.yaml, and deployments stop being scary.
Think of
mta.yamlas docker-compose for BTP: modules (what runs) plus resources (what they bind to).
Anatomy of mta.yaml
ID: bookshop
version: 1.0.0
modules:
- name: bookshop-db-deployer
type: hdb
path: gen/db
requires:
- name: bookshop-hdi-container
- name: bookshop-srv
type: nodejs
path: gen/srv
provides:
- name: srv-api
properties: { url: ${default-url} }
requires:
- name: bookshop-hdi-container
- name: bookshop-auth
- name: bookshop-approuter
type: approuter.nodejs
path: app/router
parameters:
disk-quota: 256M
memory: 256M
requires:
- name: srv-api
group: destinations
properties: { name: srv-api, url: ~{url}, forwardAuthToken: true }
- name: bookshop-auth
resources:
- name: bookshop-hdi-container
type: org.cloudfoundry.managed-service
parameters: { service: hana, service-plan: hdi-shared }
- name: bookshop-auth
type: org.cloudfoundry.managed-service
parameters: { service: xsuaa, service-plan: application,
path: ./xs-security.json }
Build and deploy, step by step
cds build --for production— compiles models and services intogen/.mbt build— packages everything intomta_archives/bookshop_1.0.0.mtar.cf login -a <api>— target your Cloud Foundry org and space.cf deploy mta_archives/bookshop_1.0.0.mtar— creates services, pushes apps, wires bindings.- Verify — check the approuter URL, log in, hit your OData endpoints.
Deploy order matters to the platform, not to you:
cf deployresolves module dependencies fromrequiresautomatically.
MTA extension descriptors
One mta.yaml rarely fits all landscapes. Extension descriptors (mtaext files) overlay environment-specific values — different service plans for dev vs prod, extra memory for QA — without forking the descriptor.
cf deploy bookshop.mtar -e prod.mtaext
Keep the base descriptor environment-neutral and push every landscape difference into extensions. The moment someone maintains two hand-edited mta.yaml files, they've created a future outage.
What cf deploy actually does
It's worth knowing the stages, because each fails differently. cf deploy uploads the MTAR, creates or updates the managed services (HDI container, XSUAA), pushes each module's app, binds services, then starts apps in dependency order.
The db-deployer runs first and must succeed before the backend starts — a schema error blocks everything downstream, which is exactly what you want. Check progress with cf deploy -i <id> --action monitor instead of refreshing the cockpit.
Troubleshooting failed deploys
- Deployer logs first — HDI errors (bad CDS, type mismatches) show in the db-deployer app logs.
- Binding failures — check resource names match between
requiresandresourcesexactly. - Version conflicts — bump the MTA version on every build; redeploying the same version confuses the deploy service.
- Stuck deployments —
cf deploy -i <operation-id> --action abort, then investigate.
One archive, full system
The MTA is the unit of deployment: database, services, router, and UI ship together, versioned together. Treat mta.yaml as code — review it like code.
Deployment stuck? Share the error in the comments.