---
description: >
  Guidance for migrating CAP Node.js applications to cds 10, covering breaking fixes, kill switches, and non-breaking changes.
---

# Migrating to cds 10

This guide covers CAP Node.js packages, that is, `@sap/cds*` and `@cap-js/*` packages.

See also [Migration Guides for CAP Java](/@external/java/migration)


[[toc]]



## CDS – Improved Checks

### Annotations Without Targets
<div id="cds-security-annotations" />

Annotations with invalid targets are generally reported as warnings by the cds compiler. However, in case of the security-related annotations, including `@restrict`, `@requires`, and `@ams.*`, this is not just a harmless issue, but may cause unauthorized access to be granted silently. To prevent such issues from being overlooked, we fixed the compiler to report such cases as errors instead of warnings.

Examples:

<!-- cds-mode: ignore -->
```cds
annotate AdmnService with @requires:'admin';            // typo: missing 'i'
annotate AdmnService.Book with @restrict: [...];        // typo: missing 's'
annotate AdminService.Books:tile with @ams.attributes: {...}; // missing 't'
```

> [!warning] Are you affected?

Try compiling your CDS models to provoke any errors as shown below:

```sh
cds compile \*
```
```js
[ERROR] Artifact “AdmnService” has not been found (in annotate:“AdmnService”)
[ERROR] Artifact “AdmnService.Books” has not been found (in annotate:“AdmnService.Books”)
[ERROR] Element “ttle” has not been found (in annotate:Books/element:“ttle”)
```

> [!tip] How to fix
If you encounter such errors, fix the typos in your annotations, or remove them if they are no longer needed.





### Invalid Defaults for Structs
<div id="cds-defaults-for-structs" />

Before cds10, you could provide invalid default values for structured elements, which were silently ignored.
With cds10, such invalid defaults result in an error.
For example, the below was accepted but ignored in `2sql` and `4odata` backends:

```cds
type struct { a: Integer; b: String; }
entity Foo { bar: struct default 22; }
```

> [!warning] Are you affected?

Try compiling your CDS models to provoke any errors as shown below:

```sh
cds compile \*
```
```js
[ERROR] Unexpected ‘default’ for a structured element with not exactly one sub element (in element: “bar”)
```

> [!tip] How to fix?
If you get such an error, remove the invalid default. This has no negative impact on your application's behavior, as it was previously ignored.



### Duplicate Elements
<div id="cds-duplicate-elements" />

Before cds10, it was possible to extend an entity with multiple aspects that contain elements with the same name, leading to unexpected behavior.
With cds10, this is now an error, to avoid such late surprises.
For example:

```cds
entity E { ID : Integer; }
extend E with { field : String; };
extend E with { field : Date; };
```

> [!warning] Are you affected?

Try compiling your CDS models to provoke any errors as shown below:

```sh
cds compile \*
```
```js
[ERROR] Duplicate definition of element “field” ...
```

> [!tip] How to fix?
If you encounter such errors, you need to adapt your model to avoid duplicate elements.
For example, you could simply remove one of the conflicting elements, or rename it.



### Keys Not Propagated into Types
<div id="cds-keys-into-types" />

With cds10, the `key` property is no longer propagated when an aspect (like `cuid`) is included in a structured `type`. An entity derived from such a type has no primary key, which causes an error when it is exposed in a service:

```cds
using { cuid } from '@sap/cds/common';

type MyType : cuid { name : String; }   // 'ID' is no longer a key here
entity MyEntity : MyType {}              // hence: no primary key

service SampleService {
  entity ExposedEntity as projection on MyEntity;   // error: no primary key
}
```

This is intended: `key` is an entity/aspect concept. A `type` is a plain structured data shape, such as an action parameter type, where `key` has no meaning.

> [!warning] Are you affected?

To check whether you are affected, generate OData metadata to provoke the error:

```sh
cds compile \* --to edmx
```
```js
[ERROR] Expected entity to have a primary key (in entity:“SampleService.ExposedEntity”)
```

> [!tip] How to fix?
Use `aspect` instead of `type` for anything that should carry a key. Entities that include an aspect keep its `key` elements. Keep `type` only where you need a plain data shape, such as action parameters.





## Potentially Breaking Fixes


| Flag / Kill Switch                                                                                                                                             | Details                                                     |        Before         |          Now          | Since                                                    |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------|:---------------------:|:---------------------:|----------------------------------------------------------|
| <Config section="cds.fiori" value="true"> bypass_draft </Config>                                                                                               | [Bypass Draft Choreography](#bypass-drafts-by-default)     | *false* | *true*  | Dec 23 |
| <Config section="cds.features" value="true"> ieee754compatible </Config>                                                                                       | [Decimals & Int64 as Strings](#decimals--int64-as-strings)   |        *false*        |        *true*         | [Jun 24](../2024/jun24#ieee754compatible)                |
| <Config section="cds.requires.db" value="real"> decimal_affinity </Config>                                                                                     | [Fixed Affinity for Decimals](#fixed-affinity-for-decimals) |      *"numeric"*      |       *"real"*        | [Jun 26](#fixed-affinity-for-decimals)                   |
| <Config section="cds.features" value="false"> legacy_srv_results </Config> <br/> <Config section="cds.features" value="true"> legacy_db_results </Config>      | [Fixed Service Results](#fixed-service-results)             |  *true* <br/> *true*  | *false* <br/> *true*  | [Jun 26](#fixed-service-results)                         |
| <Config section="cds.features" value="false"> compat_srv_getters </Config> <br/> <Config section="cds.features" value="false"> compat_texts_entities </Config> | [Fixed *srv.entities()*](#fixed-srv-entities)         |  *true* <br/> *true*  | *false* <br/> *false* | [Dec 25](../2025/dec25#cleaned-up-model-reflection-apis) |
| <Config section="cds.features" value="false"> compat_clone_appends </Config>                                                                                   | [Fixed *cds.ql.clone()*](#fixed-cds-ql-clone)               |                       |        *false*        | Jun 26                                                   |
| <Config section="cds.features" value="true"> bulk_inserts_via_rest </Config>                                                                                   | [Fixed Bulk Inserts via REST](#fixed-bulk-inserts-via-rest) |                       |        *true*         | Jun 26                                                   |




### Decimals & Int64 as Strings
<div id="ieee754compatible" />

Decimal and Int64 values cannot be represented as JavaScript numbers without risks of losing precision. Therefore many database drivers, including those for [SAP HANA](/@external/guides/databases/hana.md) and [PostgreSQL](/@external/guides/databases/postgres.md), always return such data as strings, while [SQLite](/@external/guides/databases/sqlite.md) drivers return numbers.

This database-dependent discrepancy caused surprises for CAP projects when moving to production with SAP HANA or PostgreSQL after developing with SQLite.

To avoid such late surprises we consolidated the default behavior for SQLite with the behavior of SAP HANA and PostgreSQL. This is controlled by config option <config>cds.features.ieee754compatible: true</config> (was `false` before).


::: details See also...

- [JavaScript numbers](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)
- [IEEE 754 64-bit binary format](https://en.wikipedia.org/wiki/Double-precision_floating-point_format)
- [RFC 7493](https://www.rfc-editor.org/info/rfc7493/)
- [SQLite numbers](https://sqlite.org/floatingpoint.html)
- [Why is 0.1 + 0.2 != 0.3?](https://stackoverflow.com/questions/50778431/why-does-0-1-0-2-return-unpredictable-float-results-in-javascript-while-0-2)

```js
0.1 + 0.2 //> 0.30000000000000004
(0.1).toString(2)
(0.2).toString(2)
(0.3).toString(2)
(0.1 + 0.2).toString(2)
```
```js
(0.5 + 0.25 + 0.125).toString(2)
(1/2).toString(2)
(1/2/2).toString(2)
(1/2/2/2).toString(2)
```


Yes, JavaScript has `bigint` support, but JSON doesn't. Even if CAP would custom-serialize them as numbers losslessly, clients parse these into JavaScript Numbers, losing precision.
The same applies to Java, which has dedicated `BigDecimal` and `BigInteger` types, but these are not supported by JSON or JSON clients.
Bottom line: If you want to exchange such data, always do so as strings.

:::


> [!warning] Are you affected?

You are affected by this change...

- Only in development with SQLite (no change with SAP HANA or PostgreSQL)

- If you have [`Decimal`](/@external/cds/types.md) or [`Int64`](/@external/cds/types.md) elements in your model.
   For example, search for usages of these types in your _*.cds_ files like so:
   ```shell
   grep -rni --exclude="*/node_modules/*" --include \*.cds ":\s*Decimal"
   grep -rni --exclude="*/node_modules/*" --include \*.cds ":\s*Int64"
   ```

- **And** you have custom code that does calculations with such fields, for example:
  ```js
  await INSERT.into(Books).entries({ID:1,stock:10})
  let { stock } = await SELECT.one.from (Books,1)
  stock = stock + 1 //> with SQLite: 11, with HANA: '101'
  ```

- **And/or** you have tests that compare such elements by equality, for example:
  ```js
  expect(book.stock).to.equal(10)
  expect(book).to.equal({ ..., stock:10 })
  ```

> [!tip] You are <i>not</i> affected if:

- You already had to fix those discrepancies when you went productive before.
- You already switched on <config>cds.features.ieee754compatible: true</config> in the past.
- Even if you are affected, such string concatenations were ticking time bombs.


> [!tip] How to address?

- Rewrite failing tests to avoid checking for strict numeric equality:
   ```js
   expect(book.stock).to.equal('10')
   expect(book).to.equal({ ..., stock:'10' })
   ```

- If you need to do arithmetic in JavaScript, convert the data to a Number first:
   ```js
   stock = Number(stock) + 1
   ```

- Use [`Double`](/@external/cds/types.md) instead of [`Decimal`](/@external/cds/types.md) if you can accept negligible precision loss.

- If you don't need functional correctness, for example, for prototypes or demos, revert to the former behavior by setting <config>cds.features.ieee754compatible: false</config>.

> [!tip]
> Best is to entirely avoid calculations with such fields in JavaScript, as they can always result in precision loss. Do them in the database instead. For example, this is safe: `UPDATE Books set stock = stock + 1`.



### Bypass Drafts by Default
<div id="bypass-drafts" />

With cds10, direct access to active entities is allowed by default. Previously, this required opting in via `cds.fiori.bypass_draft=true`.


> [!warning] Beware of partial requests
While this change is not breaking, check whether your application's validation logic correctly handles the additional entry points. In particular, partial _CREATE_ or _UPDATE_ requests to root entities and their composition children are now possible, for example:

   ```php
   PATCH /Orders(...) { status: 'C' } // partial update on root entity
   PATCH /Orders(...)/items(...)      // partial update to nested items
   POST /Orders(...)/items {...}      // partial create of nested items
   ```

> [!important] Opt-out with kill switch
> If you're unsure whether your application can handle the new behavior, you can opt-out from it and restore the former behavior by setting <Config>cds.fiori.bypass_draft: false</Config>.

> [!tip] Declarative constraints are safe
> If you used [declarative constraints](/@external/guides/services/constraints.md) for input validation, that is, via `@assert: (...)`, your application is already safe, as these constraints are automatically applied to all entry points, including the new ones.





### Fixed Service Results
<div id="fixed-srv-results" />

Before cds10, results of local service calls involving write operations — that is, INSERT, UPDATE, and DELETE — were undocumented and inconsistent. Sometimes the result was the number of affected rows, sometimes the input data, and sometimes an object with the `affectedRows` property indicating the affected rows.

With cds10, we fixed and consolidated this behavior as follows:

- All write operations of app services return an (array) object with property `affected` indicating the affected rows, for example, like that:
  ```js
  let { affected } = await srv.create(Books).entries(...)
  let { affected } = await srv.update(Books) .where `stock > 111` ...
  let { affected } = await srv.delete(Books) .where `stock = 0`
  ```

- Same for db services, with opt-in via <config>cds.features.legacy_db_results: false</config> for a grace period, will become the default behavior in a future release.


The change to real _array_ objects, also for `InsertResults`, lets you use object spread destructuring and standard array operations, for example, to retrieve generated primary keys from INSERTs:

```js
let [ Emily, Charlotte ] = await srv.create(Authors).entries(
  {name:'Emily Brontee'},
  {name:'Charlotte Brontee'}
)
```

This also allows support for [SQL `returning` clauses](https://sqlite.org/lang_returning.html) in future with INSERT, UPDATE, and DELETE requests.

No change was made to the results of read operations, that is, SELECTs, which return plain arrays of entries, as before.



> [!warning] Are you affected?

You are affected by this change if you have custom code that relies on the former inconsistent and undocumented results of UPDATE and DELETE operations, in particular if you have...

1. Calls to UPDATE or DELETE with app services which do expect `req.data` as result
2. Custom `after` handlers for the same which do expect `req.data` as first argument
3. Calls to UPDATE or DELETE with db services which do expect a number as result
4. Tests which expect an _object_, but not an _array_, as result of INSERTs on db level


> [!tip] How to address?

If you are affected, you should adapt your code to the new consistent results.

For cases 1 and 2, access the input data via `req.data` instead of the result, for example:

```js
this.on ('UPDATE', Books, async (req, next) => {
  let { ID, stock } = await next() // [!code --] returned req.data before
  await next(); let { ID, stock } = req.data // [!code ++] just access req.data explicitly now
})
```

For case 3, access the number of affected rows via the `affected` property of the result:

```js
let affected = await srv.update(Books) .where `stock > 111` ... // [!code --]
let { affected } = await srv.update(Books) .where `stock > 111` ... // [!code ++]
```

For case 4, adapt your tests to expect an array instead of an object, for example:

```js
expect(result).to.deep.equal ({ affectedRows:1 }) // [!code --]
expect({...result}).to.deep.equal ({ affectedRows:1 }) // [!code ++]
expect({...result}).to.deep.equal ({ affected:1 }) // [!code ++]
expect(result).to.have.property ('affected',1) // [!code ++]
```


#### Opt-in & Kill Switches

As a last resort, restore the former behavior with the following config options:

| `cds.features.`...                                               | -> restores:                                         |
|------------------------------------------------------------------|------------------------------------------------------|
| <Config section="cds.features">legacy_srv_results: true</Config> | the undocumented former behavior                     |
| <Config section="cds.features">legacy_db_results: true</Config>  | the former behavior, and still the default for cds10 |

> [!warning]
> As such kill switches restore unintended, and erroneous behavior, they should only be used as a temporary measure. It's recommended to update your code to be compatible with the new behavior. The kill switches will be removed in a future release, and relying on them for longer time may cause maintenance issues and technical debt.



### Fixed `srv.entities()`
<div id="fixed-srv-entities" />

Previously, you could call the convenient shortcuts [`srv.entities`](/@external/node.js/core-services.md#-entities), [`.types`](/@external/node.js/core-services.md#-types), [`.events`](/@external/node.js/core-services.md#-events), and [`.actions`](/@external/node.js/core-services.md#-actions) as a function. Moreover, the results returned by [`srv.entities`](/@external/node.js/core-services.md#-entities), as well as [`cds.entities`](/@external/node.js/cds-facade.md#cds-entities) accidentally included compiler-generated `*.texts` entities.
Both were undocumented and unintended, and are now fixed with cds10.

> [!warning] Are you affected?

You are affected by these fixes if you have custom code that relies on the former undocumented and unintended behavior. In particular, you can scan your code for the following patterns to check whether you are affected:

   ```shell
   grep -rni --exclude="*/node_modules/*" --include \*.js ".entities\s*(" | grep -v cds.entities
   grep -rni --exclude="*/node_modules/*" --include \*.js ".events\s*("
   grep -rni --exclude="*/node_modules/*" --include \*.js ".types\s*("
   grep -rni --exclude="*/node_modules/*" --include \*.js ".actions\s*("
   grep -rni --exclude="*/node_modules/*" --include \*.js ".texts.*.entities"
   ```
  > While these scans provide a good first approximation, they cannot be accurate.
  > You may also have used `srv.entities` in other ways, not matched by these scans.


> [!tip] How to address?

If you used the function variant, fix your code as follows:

```js
const { Books } = srv.entities() // [!code --]
const { Books } = srv.entities ('sap.capire.bookshop') // [!code --]
```
```js
const { Books } = srv.entities // [!code ++] use getter, not as function call
const { Books } = cds.entities ('sap.capire.bookshop') // [!code ++] use cds.entities
```

If you relied on `*.texts` entities in the returned results, use the [`texts`](/@external/node.js/cds-reflect#-texts) property of the respective primary entity instead:

```js
const { "Books.texts": Books_texts } = srv.entities // [!code --]
```
```js
const { Books } = srv.entities // [!code ++]
Books.texts //> use .texts property to access generated `*.texts` entities [!code ++]
```

> [!warning] Kill Switches

| `cds.features.`...                                                  | -> restores:                                   |
|---------------------------------------------------------------------|------------------------------------------------|
| <Config section="cds.features">compat_srv_getters: true</Config>    | `srv.entities()` as a function                 |
| <Config section="cds.features">compat_texts_entities: true</Config> | `*.texts` entries in results of `srv.entities` |




### Fixed `cds.ql.clone()`
<div id="fixed-cds-ql-clone" />

We fixed a bug in the implementation of [`cds.ql.clone()`](/@external/node.js/cds-ql.md#cds-ql-clone) which caused that Fluent API methods `.columns()`, `.orderBy()`, or `.groupBy()` did not append to existing clauses, as intended, but replaced instead.

Following shows the erroneous behavior (in red), and the fixed one (in green):

```js
let q1 = SELECT`a,b`.from`Foo`.where`x>1`.orderBy`a`
let q2 = cds.ql.clone(q1)
```
```js
q2.columns`c`.where`y<2`.orderBy`b`
q1.columns`c`.where`y<2`.orderBy`b`
```
```sql
q2 ⇒ SELECT       c from Foo where x>1 and y<2 order by    b -- [!code --] was wrong
q2 ⇒ SELECT a, b, c from Foo where x>1 and y<2 order by a, b -- [!code ++] now fixed
q1 ⇒ SELECT a, b, c from Foo where x>1 and y<2 order by a, b -- as expected
```



#### Are you affected?

The likelihood that you are affected is low, as `cds.ql.clone()` was rolled out in [January 26, 2026](../2026/jan26#new-cdsqlclone-method) and this only applies to a specific combination of API usages, which silently yielded wrong outcomes. You are only affected if all three of the following are true:

1. Are you using `cds.ql.clone()` at all?
    ```sh
    grep -rnw --exclude="*/node_modules/*" --include="*.js" "ql.clone"
    ```

2. You modified these using fluent API methods `.columns()`, `.orderBy()`, or `.groupBy()`
    ```sh
    grep -rnw --exclude="*/node_modules/*" --include="*.js" ".columns"
    grep -rnw --exclude="*/node_modules/*" --include="*.js" ".orderBy"
    grep -rnw --exclude="*/node_modules/*" --include="*.js" ".groupBy"
    ```
3. You relied on the erroneous behavior where these methods replaced existing clauses instead of appending to them.


#### How to address?

If you are affected, explicitly override the CQN properties instead of using the Fluent API when you don't want to append to existing clauses. For example:

```js
const { columns, orders } = cds.ql
let q1 = SELECT`a,b`.from`Foo`.where`x>1`.orderBy`a`
let q2 = cds.ql.clone(q1)
q2.SELECT.columns = columns`c,d,e`
q2.SELECT.orderBy = orders`b`
```

#### Kill Switch

As a last resort, restore the former behavior with the following config option:

| `cds.features.`...                                                 | -> restores:                  |
|--------------------------------------------------------------------|-------------------------------|
| <Config section="cds.features">compat_clone_appends: true</Config> | the erroneous former behavior |

> [!warning]
> As such kill switches restore unintended, and erroneous behavior, they should only be used as a temporary measure. It's recommended to update your code to be compatible with the new behavior. The kill switches will be removed in a future release, and relying on them for longer time may cause maintenance issues and technical debt.




### Fixed Bulk Inserts via REST
<div id="fixed-bulk-inserts-via-rest" />

CAP services generally support bulk inserts of multiple entries like so:

```js
await srv.create(Books).entries(
  { title: 'Book 1', stock: 10 },
  { title: 'Book 2', stock: 20 },
  { title: 'Book 3', stock: 30 }
)
```

And the same can be done via REST as well, for example, like that:

```http
POST /Books
Content-Type: application/json

[
  { "title": "Book 1", "stock": 10 },
  { "title": "Book 2", "stock": 20 },
  { "title": "Book 3", "stock": 30 }
]
```

However, the REST adapter did not support this properly before. It silently converted bulk creates into multiple single creates, so custom handlers for CREATE requests did not receive the complete set of entries and had no chance to optimize processing, for example, by delegating the bulk insert to the database service. This has been fixed with cds10.

#### Are you affected?

You are only affected by this change if all of the below conditions are true:

- You have a service exposed via REST
- Your clients send bulk create requests to these services
- You handle these requests with custom handlers, and ...
- you expect the former behavior of `req.data` being a single object, or
- you expect only one entry in `req.query.INSERT.entries` within these handlers.

#### How to address?

Make the custom handlers aware of bulk inserts, for example, by delegating the bulk insert to the database service:

```js
this.on ('CREATE', Books, req => INSERT.into(Books).entries(req.data))
```



#### Kill Switch

As a last resort, restore the former behavior with the following config option:

| `cds.features.`...                                                   | -> restores:                  |
|----------------------------------------------------------------------|-------------------------------|
| <Config section="cds.features">bulk_inserts_via_rest: false</Config> | the erroneous former behavior |

> [!warning]
> As such kill switches restore unintended, and erroneous behavior, they should only be used as a temporary measure. It's recommended to update your code to be compatible with the new behavior. The kill switches will be removed in a future release, and relying on them for longer time may cause maintenance issues and technical debt.




## Non-Breaking Changes

The following changes are mostly the result of refactoring or re-implementing certain CAP features to stay current with Node.js and to reduce dependencies on unmaintained third-party packages.

> [!tip] Non-breaking
They are non-breaking in the sense that they do not affect any APIs, and you should not notice any change in behavior at all. Still find below instructions on how to address potential issues, in case you encounter any.



### Node-native Fetch API
<div id="fetch-api" />

Already in [April 26](../2026/apr26#node-native-fetch-api) we replaced all direct usages of [Axios](https://axios-http.com) by using Node's native implementation of the standard [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API).

As part of this change, we now also use the native Fetch API for remote service consumption _during development_ by default, and require [SAP Cloud SDK](https://sap.github.io/cloud-sdk/docs/js/getting-started) only in production.

If you prefer to continue using SAP Cloud SDK during development as well, install the [`@sap-cloud-sdk/http-client`](https://www.npmjs.com/package/@sap-cloud-sdk/http-client) package:

```shell
npm add @sap-cloud-sdk/http-client
```


### Node-native SQLite
<div id="node-sqlite" />

In [Feb 26](../2026/feb26#native-sqlite-support), we introduced a new Node-native SQLite implementation. It reached GA and became the [default in cds10](../2026/jun26#going-native), so `better-sqlite3` is no longer installed through `@cap-js/sqlite`.

This change is not breaking, and you should not notice any difference. If needed, you can switch back to the former implementation as follows:

1. Add `better-sqlite3` as a dev dependency to your project:

```shell
npm add -D better-sqlite3
```

2. Use the <Config value="better-sqlite3"> cds.requires.db.driver </Config> option to configure the project to use that driver:

::: code-group
```json [package.json]
"cds": {
  "requires": {
    "db": {
      "driver": "better-sqlite3"
    }
  }
}
```
:::


### New Connection Pool
<div id="new-connection-pool" />

With cds10 we replaced the former connection pool implementation based on the 3rd-party package [`generic-pool`](https://www.npmjs.com/package/generic-pool)
by a new CAP-native implementation, which is fully compatible with the former.

This change is not breaking, and you should not notice any difference. If needed, you can switch back to the former implementation as follows:

1. Add `generic-pool` as a dev dependency to your project:

```shell
npm add generic-pool
```

2. Use the <Config value="generic-pool"> cds.features.pool </Config> option to configure the project to use that driver:

::: code-group
```json [package.json]
"cds": {
  "features": {
    "pool": "generic-pool"
  }
}
```
:::


### Fixed Affinity for Decimals
<div id="decimal-affinity" />

To avoid unexpected integer division effects with `Decimal` elements in SQLite, we changed the type affinity from `NUMERIC` to `REAL` by changing the generated column type from `DECIMAL` to `REAL_DECIMAL` for SQLite:

```cds
entity E { d: Decimal }
```
```sql
CREATE table E ( d DECIMAL );       -- [!code --] NUMERIC affinity
CREATE table E ( d REAL_DECIMAL );  -- [!code ++] REAL affinity
```

We can demonstrate the effect of the former _NUMERIC_ affinity with the following SQL snippet (you can run that in `sqlite3` CLI):

```sql
CREATE table T ( a REAL_DECIMAL, b DECIMAL );
INSERT into T values ( 2.0, 2.0 );
SELECT 1/a from T;
SELECT 1/b from T;
```
```sql
0.5 -- correct result with REAL affinity
0 -- unexpected integer division due to NUMERIC affinity
```

> [!tip] Non-breaking, and only for SQLite
This change is not breaking, and affects only SQLite. No changes apply to SAP HANA or PostgreSQL.
Still, if you want to restore the former behavior, you can do so by setting <config>cds.requires.db.decimal_affinity: 'numeric'</config>.



## Flags Entirely Removed

The following flags already had the new fixed behavior as their default in cds 9, but you could still revert to the former erroneous behavior.
In cds 10, these flags are removed entirely and are ignored if set in your project.

| Removed Flag                                                                   | Fixed behavior                                 | Default | Since                                                   |
|--------------------------------------------------------------------------------|------------------------------------------------|---------|---------------------------------------------------------|
| <Config section="cds.features" value="false"> consistent_params </Config>      | Confusing `req.params` -> always array now     | true    | [May 25](../2025/may25#changed-structure-of-reqparams) |
| <Config section="cds.features" value="false"> compat_save_drafts </Config>     | Draft _SAVE_ handlers called on _PATCH_ events | false   | [Sep 25](../2025/sep25#revised-fiori-support)           |
| <Config section="cds.features" value="false"> compat_assert_not_null </Config> | `ASSERT_MANDATORY` instead of `_NOT_NULL`      | false   | [Sep 25](../2025/sep25#translated-error-messages)       |

> [!caution] If you still use any of these in your project you must fix your code now!
> Follow the instructions in the linked release notes sections to fix your code.



## Change Tracking Plugin v2
<div id="change-tracking" />

The [`@cap-js/change-tracking`](https://github.com/cap-js/change-tracking) plugin has been upgraded to major version 2.0, which introduces significant improvements:

- **Database triggers** for change tracking, resulting in major performance improvements
- **Hierarchical view** of changes across parent and child entities
- [And more...](../2026/apr26#change-tracking-v2)

#### Are you affected?

- yes, if you use any 1.x version of `@cap-js/change-tracking`

#### How to address?

Upgrade to the new version by following the [migration guide](https://github.com/cap-js/change-tracking/blob/main/MIGRATION.md), which also includes an SAP HANA migration table to ensure existing change log data is retained during the upgrade.
