December 2025
Welcome to the December 2025 release of CAP. Find the most noteworthy news and changes in the following sections.Status-Transition Flows Gamma
The Status Flows feature was rolled out as Beta in November and is now promoted to Gamma level. This means it is finalized, ready to use, stable, and supported long term in the documented feature set.
annotate TravelService.Travels with @flow.status: Status actions {
acceptTravel @from: [ #Open ] @to: #Accepted;
rejectTravel @from: [ #Open ] @to: #Rejected;
deductDiscount @from: [ #Open ]; // restricted to #Open travels
}As part of this the documentation moved to Cookbook > Status Flows, got overhauled and cleaned up of implementation details which are not considered public.
Declarative Constraints Gamma
Use the new @assert annotation to express conditions using CDS Expression Language (CXL). The system validates these conditions whenever you write data. For example, the following constraints are defined on the TravelService.Travels entity:
using { TravelService } from './travel-service';
annotate TravelService.Travels with {
Description @assert: (case
when length(Description) < 3 then 'Description too short'
end);
Customer @assert: (case
when Customer is null then 'Customer must be specified'
when not exists Customer then 'Customer does not exist'
end);
BeginDate @mandatory @assert: (case
when BeginDate > EndDate then 'ASSERT_BEGINDATE_BEFORE_ENDDATE'
when exists Bookings [Flight.date < Travel.BeginDate]
then 'ASSERT_BOOKINGS_IN_TRAVEL_PERIOD'
end);
}Learn more about Declarative Constraints
New @hierarchy Annotation
Annotations for hierarchical tree views have been greatly streamlined. Simply annotate a respective entity with the new @hierarchy annotation like this:
annotate AdminService.Genres with @hierarchy;Which replaces all of these elaborate OData annotations you had to add previously:

The rest stays as before, and as documented in Serving Fiori UIs – Hierarchical Tree Views. Find in the guide also additional details and usage options about the new @hierarchy annotation.
New cds export Beta
Use cds export to create API client packages from CDS service definitions. For example, given a service definition like that:
service sap.capire.flights.data {
@readonly entity Flights as projection on my.Flights;
@readonly entity Airlines as projection on my.Airlines;
@readonly entity Airports as projection on my.Airports;
}We can create an API client package using the following command:
cds export srv/data-service.cdsThe output is a full-featured CAP reuse package, which can be published to npm registries:
npm publish ./apis/data-service... and consumed by other CAP projects using standard npm add and npm update:
npm add @capire/xflights-dataIn addition cds export applies CAP plugin techniques to the generated package, so consumers benefit from plug & play, without any further configuration required.
Why use cds export?
Instead of exporting APIs to OData EDMX and cds importing them to consuming apps, cds export creates ready-to-use API client packages, with lossless CDS API models.
CDS Language & Compiler
Loading from app/* subfolders
By default, cds build or cds serve now automatically fetch and load all .cds files not only from the ./app folder itself but also from all ./app/* subfolders in there. For example, if you have Fiori apps organized in subfolders like shown in the snapshot below, all the .cds files will be loaded automatically.

Thereby we eliminate the need to add an ./app/index.cds with using directives for each file in subfolders like that:
// Import all .cds files from common folder
using from './common/code-lists';
using from './common/common';
using from './common/labels';
// Import all .cds files from travels folder
using from './travels/capabilities';
using from './travels/field-control';
using from './travels/layouts';You can disable this by setting cds.folders.apps: false. You can apply the same for other folders by e.g. cds.folders.srvs: srv/*.
Learn more about the CAP project structure.
Enums in Annotation Expressions
Up to now, you could use enum symbols in annotation expressions only for enums defined in CDS. As value for an OData annotation, you had to provide the actual value and then explain the meaning of these funny numbers. Now, you can directly use the enum symbols:
entity Travel {
key TravelUUID : UUID;
status : String(1) enum { Open = 'O'; Accepted = 'A'; Canceled = 'X'; };
// 1 is ReadOnly, 7 is Mandatory
@Common.FieldControl: (status = #Accepted ? 1 : 7)
@Common.FieldControl: (status = #Accepted ? #ReadOnly : #Mandatory)
bookingFee : Decimal(16,3) default 0;
}Learn more about Annotation Expressions.
Node.js
Direct CRUD on Draft-enabled Entities Beta
With cds.fiori.direct_crud:true, the Node.js runtime now allows direct CRUD requests to draft-enabled entities. For example, instead of having to follow the draft request sequence of EDIT, PATCH, and SAVE, you can send direct UPDATE requests to the so-called active entity.
Learn more about draft-specific events.
In such direct requests, the additional key IsActiveEntity defaults to true, which allows you to omit it:
POST {{server}}/odata/v4/travel/Travels
{ "ID": 4711 }PUT {{server}}/odata/v4/travel/Travels(ID=4711)
{ "Description": "Fun times!" }No code changes required
Note that with this feature, the POST request creates the active entity. Hence, even though the feature works seamlessly with existing implementations and also SAP Fiori elements adjusts on the fly, it may affect your tests.
Learn more about direct CRUD on draft-enabled entities.
Improved Event Queue Processing
We consolidated event queue processing into a default queue and custom queues (if configured).
This change is transparent for projects except for minor content changes in the technical data structure (cds.outbox.Messages) that may show up in custom-built extensions for managing the Dead Letter Queue.
Further, we increased the db-related guarantee from at least once to exactly once. That is, the system only commits database changes from event processing if it successfully processes the event, and vice-versa.
Learn more about Event Queues in Node.js
Cleaned-up Model Reflection APIs
The following function usages are officially deprecated and will be removed in the next major version 10.
| Deprecated Usage | Official Usage |
|---|---|
srv.entities() | srv.entities/ cds.entities() |
srv.types() | srv.types |
srv.events() | srv.events |
srv.actions() | srv.actions |
Further from version 10 onwards, the .texts entities will not be included in the srv.entities variants anymore. Use the texts property of the respective entity instead.
| Deprecated Usage | Official Usage |
|---|---|
CatalogService['Books.texts'] | CatalogService.Books.texts |
You can enforce that behavior already today with cds.features.compat_texts_entities:false.
Java
Important Changes ❗️
Deep Updates for Draft
So far, for draft-enabled entities, deep updates were only supported for the active entities. Now, you may also execute deep updates on the inactive entities provided that the update statement includes the keys for entities to be updated. Searched updates will be rejected.
The following example shows the recommended way to do this:
DraftService draftService = ...
Orders entry = Orders.create();
entry.setId(123);
entry.setItems(...); // Some info about items
CqnUpdate deepUpdate =
Update.entity(ORDERS, o -> o.filter(f -> f.IsActiveEntity().eq(false)))
.entry(entry);
draftService.run(deepUpdate);Miscellaneous
API for Aliasing CqnValue
The CqnValue interface received a new as(String alias) method to create aliased values directly. This makes it easier to build queries with aliased values, such as predicate expressions on the select list:
CqnExpression xpr = cdsModel.getEntity(BOOKS.CDS_NAME).getAnnotationValue("@xpr", CQL.FALSE);
Select.from(BOOKS).columns(xpr.as("annotatedXpr")); Tools
cds up Convenience for Kyma
If your project contains Helm deployment resources and no mta.yaml cds up will default to Kubernetes and you do not need to specify the --to k8s option anymore.
cds up --to k8s
cds upLearn more about Kyma Deployment.
Plugins
@sap/cds-rfc
The Node.js plugin @sap/cds-rfc now supports multitenancy.