The Chart Templates Behind Your CAP Kyma Deployment

When you run cds add kyma on a CAP project, cds-dk generates a Helm umbrella chart whose Chart.yaml declares a list of dependencies. If you've opened that file, you've seen something like this:

Copy
apiVersion: v2
name: bookshop
description: A simple CAP project.
type: application
version: 1.0.0
appVersion: 1.0.0
annotations:
  app.kubernetes.io/managed-by: cds-dk/helm
dependencies:
  - name: web-application
    alias: srv
    version: ">0.0.0"
  - name: service-instance
    alias: hana
    version: ">0.0.0"
  - name: content-deployment
    alias: hana-deployer
    version: ">0.0.0"
  - name: service-instance
    alias: xsuaa
    version: ">0.0.0"

A natural question follows: how many of these chart templates exist, and what can I configure in each? This post answers exactly that, based on inspecting the @sap/cds-dk module itself (v10.x), and gives you the full list of knobs with practical examples (as of July 2026).

Series — SAP BTP Kyma Runtime:

  1. Preparing Your Environment For SAP BTP Development on Kyma Runtime
  2. Deploying Your First CAP Application on SAP BTP Kyma Runtime
  3. Creating BTP Service Instances on SAP BTP Kyma Runtime with the Service Operator
  4. Binding BTP Service Instances to your CAP Application with Kyma Runtime
  5. The Chart Templates Behind Your CAP Kyma Deployment (this post)
  6. Creating roles for your CAP Application on SAP BTP Kyma Runtime
  7. Using Istio Gateway as Entry Point in SAP BTP Kyma Runtime

Three Chart Templates

Here's the key insight that trips up most developers: no matter how long your dependencies: list is, it is built from only three reusable subcharts (as of July 2026). They ship inside the cds-dk Helm plugin:

Copy
@sap/cds-dk/lib/build/plugins/helm/files/subcharts/
├── web-application/       # chart version 2.x
├── service-instance/      # chart version 1.x
└── content-deployment/    # chart version 1.x

Here a description of each, and the typical alias you might see in your umbrella chart's Chart.yaml:

Subchart (name) What it deploys Typical alias
web-application A runnable workload: Deployment + Service, plus optional APIRule/VirtualService, HPA, RBAC, NetworkPolicy, PodDisruptionBudget and service bindings. srv, approuter
service-instance A BTP service instance and binding via the SAP BTP Service Operator (ServiceInstance + ServiceBinding). hana, xsuaa, destination, connectivity, html5-apps-repo-host
content-deployment A one-off Job that deploys content (e.g. the HANA table/data deployer). hana-deployer

The name field selects the template; the alias field names the instance. That's why the example at the top has four dependencies but only three distinct names — service-instance appears twice, once aliased as hana and once as xsuaa. You can add as many service-instance entries as you have BTP services to provision.

Not subcharts, but worth knowing: the plugin also carries helpers for approuter, connectivity and html5-repo. These inject a ConfigMap into the umbrella chart's own templates/ folder — they are not standalone subcharts. The approuter and html5-apps-deployer workloads themselves still run through the web-application chart.

You configure each subchart from the umbrella chart's values.yaml, keyed by the alias. If you're new to how parent charts pass values down to their children, see Helm for Kubernetes — Managing Dependencies.

Copy
# values.yaml (umbrella chart)
srv:            # -> configures the web-application subchart aliased as "srv"
  replicaCount: 2
hana:           # -> configures the service-instance subchart aliased as "hana"
  serviceOfferingName: hana
  servicePlanName: hdi-shared

Now let's break down the knobs for each template.

The "web-application" — Your Runnable Workload

This is the workhorse. It renders a Deployment and a Service, and depending on your values, an APIRule to expose it, an HPA to scale it, RBAC, a NetworkPolicy, and service bindings that mount BTP credentials into the pod.

The Knobs

Key Default Purpose
replicaCount 1 Number of pods in the Deployment.
port 8080 Container port the app listens on.
image.repository / image.registry / image.tag Container image coordinates.
imagePullPolicy Always / IfNotPresent / Never.
command / args Override the container entrypoint.
env / envFrom {} / [] Environment variables (inline, or from Secret/ConfigMap).
resources.requests / resources.limits CPU / memory / ephemeral-storage requests & limits.
additionalVolumes [] Extra volumes + mounts.
runAsUser UID for the container process.
readOnlyRootFilesystem Harden the container filesystem.
expose.enabled true Whether to create an APIRule and expose the app externally.
expose.host / expose.hosts Custom DNS host(s) for inbound traffic.
expose.gateway kyma-system/kyma-gateway Istio gateway used for incoming traffic.
expose.rules noAuth on /* APIRule access rules (methods, path, CORS policy).
istio.enabled true Whether the pod joins the Istio mesh (required for APIRule v2).
health.liveness / health.readiness /healthz Probe paths, thresholds and timeouts.
health.port Separate port for health probes, if different from port.
startupTimeoutSeconds 30 Grace window for the app to start before liveness kicks in.
terminationGracePeriodSeconds 30 SIGTERM grace period.
hpa.enabled / hpa.minReplicas / hpa.maxReplicas false / 1 / 3 Horizontal Pod Autoscaler.
hpa.behavior / hpa.metrics Custom scaling metrics/behaviour.
availability.podDisruptionBudget maxUnavailable: 10% PDB for voluntary disruptions.
availability.topologySpreadConstraints zone + hostname Spread pods across zones/nodes.
networkSecurity.enabled true Generate a NetworkPolicy.
networkSecurity.ingress / additionalPorts [] Allowed ingress sources and extra ports.
rbac.role / rbac.clusterRole / rbac.rules {} Attach or create RBAC (only one of the three).
bindings see below BTP service bindings mounted into the pod.
prometheus.enabled / prometheus.path / prometheus.port false / /metrics Prometheus scrape annotations.
otlp.metrics / otlp.traces / otlp.logs enabled: true OpenTelemetry endpoints (Kyma Telemetry).
sidecars Additional containers in the pod (image, env, resources, health).
nodeSelector / nodeAffinity Pod scheduling constraints.
annotations.deployment / annotations.service {} Extra annotations on the Deployment/Service.
nameOverride / fullnameOverride Override generated resource names.
global.imagePullSecret.name / global.image image-pull-secret Cluster-wide image pull settings (shared with all subcharts).

Example — a scalable, bound CAP service

Copy
# values.yaml (umbrella chart)
srv:
  replicaCount: 2
  image:
    repository: my-registry/bookshop-srv
    tag: "1.0.0"
  resources:
    requests:
      cpu: 200m
      memory: 256M
    limits:
      cpu: 500m
      memory: 512M
  hpa:
    enabled: true
    minReplicas: 2
    maxReplicas: 5
  expose:
    enabled: true
    rules:
      - path: /*
        methods: [GET, POST, PUT, PATCH, DELETE]
        noAuth: false          # require auth via the mesh
  bindings:
    hana:
      serviceInstanceName: hana
    xsuaa:
      serviceInstanceName: xsuaa
  health:
    liveness:
      path: /health
    readiness:
      path: /health

The bindings block is the bridge between this workload and your service-instance dependencies: each entry references a serviceInstanceName and mounts its credentials Secret into the pod. See Creating BTP Service Instances on SAP BTP Kyma Runtime with the Service Operator for how those instances are created.

The "service-instance" — Provisioning BTP Services

This chart is the declarative counterpart to cf create-service. It renders a ServiceInstance and (optionally) a ServiceBinding custom resource for the SAP BTP Service Operator to reconcile.

The Knobs

Key Default Purpose
serviceOfferingName The BTP service offering (e.g. hana, xsuaa, destination).
servicePlanName The plan (e.g. hdi-shared, application, lite).
externalName Name of the instance as it appears in BTP.
btpAccessCredentialsSecret Secret holding the subaccount credentials for provisioning.
customTags Tags copied into the binding secret under tags.
parameters Service-specific provisioning parameters (inline map).
jsonParameters Same, provided as a JSON string.
parametersFrom Pull parameters from a Secret/ConfigMap key.
bindings see below One or more ServiceBindings, with rotation policy.
bindings.defaultProperties.credentialsRotationPolicy disabled Automatic credential rotation (rotationFrequency, rotatedBindingTTL).
annotations.serviceInstance / annotations.serviceBinding {} Extra annotations on the CRs.
nameOverride / fullnameOverride Override generated resource names.

Example — an XSUAA instance with parameters

Copy
# values.yaml (umbrella chart)
xsuaa:
  serviceOfferingName: xsuaa
  servicePlanName: application
  parameters:
    xsappname: bookshop
    tenant-mode: dedicated
    role-templates:
      - name: Viewer
        description: View books
  bindings:
    xsuaa:
      credentialsRotationPolicy:
        enabled: true
        rotationFrequency: "720h"    # rotate every 30 days
        rotatedBindingTTL: "24h"     # keep the old binding for 24h

And a minimal HANA instance:

Copy
hana:
  serviceOfferingName: hana
  servicePlanName: hdi-shared

The "content-deployment" — One-Off Jobs

Some BTP scenarios need a task that runs once to push content — the classic example being the HANA HDI deployer, which creates tables and loads initial data. This chart renders a Kubernetes Job (plus a ServiceAccount and any bindings the job needs).

The Knobs

Key Default Purpose
image.repository / image.registry / image.tag The deployer image to run.
command / args Override the job's entrypoint.
env / envFrom {} / [] Environment variables for the job.
resources.requests / resources.limits CPU / memory / ephemeral-storage.
bindings BTP service bindings the job needs (e.g. the HANA instance).
ttlDaysAfterFinished 14 Auto-clean the Job this many days after it completes.
serviceAccountName ServiceAccount for the job pods.
runAsUser UID for the container process.
readOnlyRootFilesystem Harden the container filesystem.
nodeSelector / nodeAffinity Scheduling constraints.
annotations.job {} Extra annotations on the Job/pods.
nameOverride / fullnameOverride Override generated resource names.
global.imagePullSecret.name image-pull-secret Shared image pull settings.

Example — a HANA deployer job

Copy
# values.yaml (umbrella chart)
hana-deployer:
  image:
    repository: my-registry/bookshop-hana-deployer
    tag: "1.0.0"
  bindings:
    hana:
      serviceInstanceName: hana
  ttlDaysAfterFinished: 7

Putting It All Together

A typical bookshop deployment wires all three templates together — the deployer runs once to set up the database, the service instances provision HANA and XSUAA, and the web-application runs your CAP service bound to both:

Copy
# Chart.yaml
dependencies:
  - name: web-application
    alias: srv
    version: ">0.0.0"
  - name: service-instance
    alias: hana
    version: ">0.0.0"
  - name: content-deployment
    alias: hana-deployer
    version: ">0.0.0"
  - name: service-instance
    alias: xsuaa
    version: ">0.0.0"
Copy
# values.yaml
srv:
  image: { repository: my-registry/bookshop-srv, tag: "1.0.0" }
  bindings:
    hana: { serviceInstanceName: hana }
    xsuaa: { serviceInstanceName: xsuaa }

hana:
  serviceOfferingName: hana
  servicePlanName: hdi-shared

hana-deployer:
  image: { repository: my-registry/bookshop-hana-deployer, tag: "1.0.0" }
  bindings:
    hana: { serviceInstanceName: hana }

xsuaa:
  serviceOfferingName: xsuaa
  servicePlanName: application

Finding This For Yourself

Everything here came straight from the module. To inspect the shipped subcharts and their default values on your own machine:

Copy
# Locate your cds-dk install
CDS=$(npm root -g)/@sap/cds-dk

# List the three subchart templates
ls "$CDS/lib/build/plugins/helm/files/subcharts"

# Read the default values for any of them
cat "$CDS/lib/build/plugins/helm/files/subcharts/web-application/values.yaml"

After cds add kyma and after building the project, the same charts also land in your project's gen/chart/charts/ folder, so you can browse them right next to your code.