SuperAPI AI Directory

cds10-migration

Coding & development

View repository

Updated 10-16 02:37

About this skill

CDS 10 Migration — CAP Best Practices

Primary reference: https://cap.cloud.sap/docs/releases/2026/jun26
Migration guide: https://cap.cloud.sap/docs/releases/migration/cds10

Package version requirements

// package.json — use matching major versions for all @cap-js packages
{
  "engines": { "node": ">=22" },
  "dependencies": {
    "@sap/cds":       "^10",
    "@sap/cds-dk":    "^10",
    "@sap/cds-mtxs":  "^4",
    "@cap-js/sqlite": "^3",
    "@cap-js/hana":   "^3"
  }
}

⚠️ Don't mix versions: Never use @sap/cds 10.x with @sap/cds-mtxs 3.x or @cap-js/hana 2.x — versions must align.

CAP Java 5 requires JDK 21 (minimum) or JDK 25 (recommended) and Spring Boot 4.1+.


Use cds upgrade to check your project

npm install -g @sap/cds-dk
cds upgrade

The cds upgrade tool (Alpha in CDS 10) scans your project for breaking changes and provides migration guidance for each finding.


Step-by-step migration checklist

Step 1: Meet Node.js requirements

Node.js version Status in CDS 10
Node.js v20 Not supported (EOL April 2026)
Node.js v22 Minimum required
Node.js v24 Recommended (Active LTS)
Node.js v26 Already tested, usable in dev
node --version   # must be >= 22

Step 2: Upgrade packages

npm install @sap/cds@latest @sap/cds-dk@latest
npm install @cap-js/sqlite@latest @cap-js/hana@latest
npm install @sap/cds-mtxs@latest   # if you use multitenancy

Step 3: Fix CDS compiler errors — improved checks

The CDS compiler now reports security annotation mismatches as errors (not warnings):

// ❌ Typo in artifact name — was a warning, now an error
annotate AdmnService with @requires: 'admin';  // "AdmnService" doesn't exist

// ❌ Duplicate element extension — now an error
extend MyEntity with { field: String; };
extend MyEntity with { field: Date; };  // duplicate!

// ❌ Invalid default on structured element — now an error
type Address { street: String; city: String; }
entity Foo { addr: Address default 'Berlin'; }

Run to find all errors:

cds compile '*'

Step 4: Handle breaking behavior changes

A. Bypass Drafts by Default (bypass_draft: true)

Impact: Direct access to active entities now skips draft choreography by default.

// CDS 10: These access ACTIVE entity directly (no draft processing)
GET /odata/v4/Orders(123)        // ✓ reads active directly
PATCH /odata/v4/Orders(123)      // ✓ updates active directly
DELETE /odata/v4/Orders(123)     // ✓ deletes active directly

If you need the old behavior (always go through draft choreography):

// in srv/cat-service.js
cds.fiori.bypass_draft = false

Handler impact: Validation handlers must now handle both draft AND active entity paths:

this.on('PATCH', Orders, req => {
  // Called for: PATCH /draft/Orders(id) AND PATCH /Orders(id) in CDS 10
  // (only for draft path before CDS 10)
})

B. Consolidated Write Results

INSERT now returns an iterable array with generated keys:

const result = await INSERT.into(Products).entries(
  { title: 'Book 1', price: 29.99 },
  { title: 'Book 2', price: 19.99 }
)
const [book1, book2] = [...result]  // generated IDs

UPDATE/DELETE return { affected: number }:

const { affected } = await UPDATE(Products, id).with({ price: 24.99 })
const { affected: deleted } = await DELETE.from(Orders).where(...)

Handler note: Access input via req.data in handlers — don't rely on the return value.

C. IEEE754Compatible enabled by default

Decimal and Int64 fields now return as strings (not numbers):

// CDS 9:  { amount: 123.45 } — loss of precision for large decimals
// CDS 10: { amount: "123.45" } — full precision preserved, type is string

In TypeScript/client code, parse as needed:

const amount = parseFloat(order.amount)  // string → number
const price = new Decimal(order.price)   // string → Decimal

Disable if needed (⚠️ not recommended):

// srv/cat-service.js
cds.env.build.ieee754compatible = false

D. srv.entities — now a getter, not a callable

// CDS 9: srv.entities was a method
const { Books } = srv.entities()  // ❌ error in CDS 10

// CDS 10: srv.entities is a getter
const { Books } = srv.entities    // ✓ correct

E. Removed compatibility flags

These flags have been removed in CDS 10:

Flag Alternative
cds.compat.consistent_params Already built-in
cds.compat.compat_save_drafts Use cds.fiori.bypass_draft: false instead
cds.compat.assert_not_null Stricter validation now default

CAP Java migration (Spring Boot 4.1+)

Requirement CDS 9 CDS 10
JDK 17, 21 21 minimum, 25 recommended
Spring Boot 3.2, 4.0 4.1 minimum
Spring Security 6.x 7.0+
Maven 3.8.8+ 3.9.14+

Automatic migration with OpenRewrite

CAP Java 5 provides OpenRewrite recipes that automate the bulk of required code changes:

mvn org.openrewrite.maven:rewrite-maven-plugin:run \
  -Drewrite.recipeArtifactCoordinates=com.sap.cds:cds-services-recipes:5.0.0 \
  -Drewrite.activeRecipes=com.sap.cds.services.migrations.Cap_5.0

This handles most deprecated API replacements and property migrations automatically.

<properties>
  <maven.compiler.source>21</maven.compiler.source>
  <maven.compiler.target>21</maven.compiler.target>
  <spring-boot.version>4.1.0</spring-boot.version>
</properties>

<dependencies>
  <!-- CDS 10 -->
  <dependency>
    <groupId>com.sap.cds</groupId>
    <artifactId>cds-spring-boot-starter</artifactId>
    <version>3.0.0</version>
  </dependency>
  
  <!-- Spring Boot 4.1 with Spring Security 7.0 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
  </dependency>
</dependencies>

Going Native — third-party dependencies removed

In CDS 10 these replacements are defaults (no longer opt-in feature flags):

Removed dependency Replaced by
axios Node-native Fetch API
better-sqlite3 Node-native node:sqlite
generic-pool Built-in connection pool
@sap-cloud-sdk/http-client Native Fetch (in dev; Cloud SDK still needed for production OAuth)

Total footprint reduction: ~112 packages, ~23 MB. No code changes needed.

In production or hybrid scenarios that need BTP Destination OAuth: @sap-cloud-sdk/http-client is still required — add it explicitly with npm add @sap-cloud-sdk/http-client.


Vitest migration (Jest deprecated)

CDS 10 recommendation: Use Vitest instead of Jest:

npm uninstall jest
npm install --save-dev vitest chai
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import { createRequire } from 'module'

const require = createRequire(import.meta.url)

export default defineConfig({
  test: {
    globals: true,
    testEnvironment: 'node',
    coverage: {
      provider: 'v8'
    }
  }
})

Why: Chai v6 (used in CAP tests) has full support only with Vitest; Jest has partial compatibility.


Health check — verify your migration

# 1. Compile without errors
cds compile '*'

# 2. All tests pass
npm test

# 3. Handlers use class-based pattern with super.init()
grep -r "class.*ApplicationService" srv/
grep -r "return super.init()" srv/

# 4. No old bypass_draft flag references
grep -r "bypass_draft" . --include="*.js"

# 5. No remaining Jest imports (should be Vitest)
grep -r "from 'jest'" test/

# 6. No srv.entities() calls (should be srv.entities)
grep -r "srv.entities()" srv/

Quick migration path

  1. Node.js: Upgrade to v22+
  2. Packages: npm install @sap/cds@latest
  3. Compile: cds compile '*' — fix all errors
  4. Tests: Update Jest → Vitest (if applicable)
  5. Handlers: Verify return super.init() in init()
  6. Results: Handle new write result shapes (INSERT iterable, UPDATE/DELETE { affected })
  7. Drafts: Test if bypass_draft: true default works or needs false
  8. CAP Java: Upgrade JDK to 21, Spring Boot to 4.1
  9. Run tests: npm test
  10. Deploy: Follow your deployment pipeline

Common mistakes to avoid

  • ❌ Mixing @sap/cds 10.x with @cap-js/sqlite 2.x or @sap/cds-mtxs 3.x
  • ❌ Forgetting Node.js v22 requirement (v20 is EOL)
  • ❌ Not handling new write result shapes (INSERT iterable, UPDATE/DELETE { affected })
  • ❌ Calling srv.entities() instead of using srv.entities as getter
  • ❌ Not updating validation handlers for bypass_draft: true default
  • ❌ Continuing with Jest instead of migrating to Vitest
  • ❌ Using old CAP Java (JDK 17) — must be 21+