{"ref":"capability:caching","page":"/capabilities/caching","json":"/capabilities/caching.json","generated":"2026-10-26","drafted_with_ai":true,"entity":{"id":"caching","name":"Caching","domain":"data-and-persistence","ecosystems":["cap","btp","abap"],"universal":true,"description":"Holding the result of an expensive read so the next one is cheap. This spans four different things people call caching — HTTP response caching, query result caching, remote service response caching, and application-level memoisation. They are not interchangeable, and picking the wrong one is the usual cause of stale-data bugs in multitenant apps.","short":"Holding the result of an expensive read so the next one is cheap","core_coverage":{"state":"core-and-community","assessed_at":"2026-09-17","relationship":"unassessed","what_core_does":"CAP supports HTTP cache validation through ETags. CAP Java also sets Cache-Control max-age headers on annotated stream properties.","where_it_stops":"ETags validate a resource version and the Java annotation controls HTTP response freshness; these mechanisms do not specify an application result-cache store or a replicated service database.","community_adds":"[cds-caching](artifact:cds-caching) retains query, request and function results; [@cap-js-community/common](artifact:cap-js-community-common) replicates service data into SQLite. [cds-data-federation](artifact:mikezaschka-cds-data-federation) exposes response and entity-snapshot caching for federated data. In cds-caching, tenant-aware keys are enabled automatically in MTX unless explicitly disabled.","sources":[{"url":"https://cap.cloud.sap/docs/guides/services/served-ootb","title":"capire — Generic Service Providers","checked":"2026-09-17","quote":"caching techniques using ETags"},{"url":"https://cap.cloud.sap/docs/guides/uis/fiori","title":"capire — Cache Control in Java","checked":"2026-09-17","quote":"The Cache Control feature is currently supported only on the Java runtime."},{"url":"https://github.com/mikezaschka/cds-caching/blob/main/README.md","title":"cds-caching — README","checked":"2026-09-17","quote":"Transparently cache CQN queries, CAP requests, or function calls"},{"url":"https://github.com/cap-js-community/common/blob/main/README.md","title":"CAP Node.js Community Common — Replication Cache","checked":"2026-09-17","quote":"The replication cache allows to cache a service (e.g. db service) into a tenant-aware SQLite database."},{"url":"https://github.com/mikezaschka/cds-caching/blob/main/docs/security.md","title":"cds-caching — Tenant and user isolation","checked":"2026-09-17","quote":"`isTenantAware` defaults to `true` when multitenancy is detected, so tenants are separated by default in MTX mode."},{"url":"https://github.com/mikezaschka/cds-data","title":"cds-data — README","checked":"2026-09-17","quote":"Federation optionally layers [cds-caching](https://github.com/mikezaschka/cds-caching) on delegate or replicate."}]},"history":[{"date":"2026-08-31","field":"core_coverage.state","from":"left-open-on-purpose","to":"core-and-community","reason":"States renamed to describe who is present rather than to interpret intent. left-open-on-purpose asserted a motive; core-and-community states a fact, with relationship carrying the intent separately."},{"date":"2026-08-31","field":"core_coverage.what_core_does","from":"The runtime provides in-process memoisation for the lifetime of a single application instance.","to":"","reason":"Removed: no source found. The sentence asserted an in-process cache with the lifetime of an application instance, and nothing in capire says so. An unsourced claim about the core is exactly what rule 10 forbids, and it was load-bearing — it is the reason the caching options exist."},{"date":"2026-08-31","field":"core_coverage.relationship","from":"narrow-by-design","to":"unassessed","reason":"narrow-by-design requires saying what the core does and where it stops. With the unsourced core claim removed there is no basis for either, and 'narrow by design' asserts an intent we cannot evidence. Unassessed is the honest state until someone checks."},{"date":"2026-09-07","field":"gap","from":"open since 2026-02-01","to":"removed","reason":"Seed text. It claimed nothing credible existed for invalidation driven by CDS change events, which cds-caching answers, so the note described the corpus before that entry rather than the ecosystem."},{"date":"2026-09-08","field":"core_coverage.sources[0].url","from":"https://cap.cloud.sap.com","to":"https://cap.cloud.sap/docs/","reason":"cap.cloud.sap.com does not resolve — the domain is cap.cloud.sap. Found by the first run of the link checker; the citation had carried a checked date since it was written, which is what a date alone is worth."},{"date":"2026-09-14","field":"ecosystems","from":"cap, ui5, integration, btp","to":"cap, ui5, integration, btp, abap","reason":"ABAP-CACHE-BOX in this batch generates singleton cache classes over hashed tables for ABAP programs, which is application-level memoisation on the ABAP door."},{"date":"2026-09-15","field":"ecosystems","from":"cap, ui5, integration, btp, abap","to":"cap, btp, abap","reason":"UI5 and Integration were listed with no coverage, no framing and no provider behind either door, so CAP's community-only reading painted the UI5 map as if a CAP plugin were a UI5 answer. The concern stays on the doors that have been assessed."},{"date":"2026-09-15","field":"core_coverage.community_adds","from":"With no answer from the core, there are community plugins in place to address caching needs.  One is a replication cache moving external data closer to a CAP app and the other one a caching service built for CDS, which knows about keys, invalidation and tenants, and general-purpose stores wired in by hand. T","to":"Two CAP plugins answer it: [cds-caching](artifact:cds-caching) caches query results and remote service responses and puts the tenant into its cache keys under multitenancy, and the replication cache of [@cap-js-community/common](artifact:cap-js-community-common) copies a service into a tenant-aware SQLite database.","reason":"The sentence was cut off mid-word. Rewritten to name the two CAP plugins by their entries, and the multitenancy warning moved here as core_coverage.note: node-cache leaves the graph because its own documentation names no SAP stack, and the lesson it carried is about every hand-wired general-purpose cache, not about one library."},{"date":"2026-09-17","field":"core_coverage, framing_by_ecosystem.cap, facets","from":"Blanket absence of core caching; no comparison facets","to":"HTTP caching distinguished from result caching, replication and backing storage","reason":"Official ETag and Java cache-control documentation establish core HTTP caching support; maintainer documentation supplies conditional comparison facts."},{"date":"2026-09-17","field":"core_coverage.state","from":"community-only","to":"core-and-community","reason":"Official CAP documentation establishes ETag HTTP caching and Java stream Cache-Control support; preserve the tenant-key isolation warning with the documented MTX default."},{"date":"2026-09-17","field":"core_coverage.note, core_coverage.community_adds","from":"Core note mixed tenant-key guidance with named community and BTP alternatives","to":"Removed core note; placed the sourced cds-caching MTX default in community_adds","reason":"User requires SAP ships to describe only core behavior and limits. Provider guidance belongs under The community adds. The broad tenant-key prescription is omitted; sourced tenant conditions remain on provider edges. Redis remains the served BTP option."},{"date":"2026-10-17","field":"description","from":"Holding the result of an expensive read so the next one is cheap. In CAP this spans four different things people call caching — HTTP response caching, query result caching, remote service response caching, and application-level memoisation. They are not interchangeable, and picking the wrong one is the usual cause of stale-data bugs in multitenant apps.","to":"Holding the result of an expensive read so the next one is cheap. This spans four different things people call caching — HTTP response caching, query result caching, remote service response caching, and application-level memoisation. They are not interchangeable, and picking the wrong one is the usual cause of stale-data bugs in multitenant apps.","reason":"Keep the default capability wording neutral; preserve the previous wording in framing_by_ecosystem.cap. Maintainer-requested scope audit."}],"coverage_by_ecosystem":{"btp":{"state":"core-only","assessed_at":"2026-09-09","what_core_does":"[Redis](external:redis) on SAP BTP, in a hyperscaler edition and an older one, is the managed cache an application binds; there is no application-level caching layer in the platform, the store is the answer.","sources":[{"url":"https://github.com/SAP-samples/btp-service-metadata/blob/main/v1/developer/redis-cache.json","title":"Redis, hyperscaler option — SAP btp-service-metadata v1","checked":"2026-09-09"},{"url":"https://github.com/SAP-samples/btp-service-metadata/blob/main/v1/developer/redis.json","title":"Redis on SAP BTP — SAP btp-service-metadata v1","checked":"2026-09-09"}]},"abap":{"state":"core-and-community","assessed_at":"2026-09-14","what_core_does":"Table buffering keeps rows of a database table in the shared memory of the application server, switched on and typed as single-record, generic or full buffering in the table's technical settings, and ABAP SQL reads use the buffer without code.","where_it_stops":"At table rows. A value a program computes or an object it builds is not a table read, so holding it for reuse within the program is the program's own code.","relationship":"unassessed","sources":[{"url":"https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abenddic_database_tables_buffer.htm","title":"ABAP Keyword Documentation 7.52 — Table Buffering of Database Tables","checked":"2026-09-14","quote":"If possible, the database interface redirects any reads to the table buffer in the shared memory of the application server."},{"url":"https://github.com/SAP-samples/abap-cheat-sheets/blob/main/32_Performance_Notes.md","title":"ABAP cheat sheets — Performance Notes","checked":"2026-09-14","quote":"The table buffering is applied implicitly when the database is accessed using ABAP SQL."}],"community_adds":"Application-level memoisation: macros that generate a singleton cache class per data type or object type, backed by a hashed table."}},"framing_by_ecosystem":{"abap":{"description":"On ABAP the platform's cache is the table buffer on the application server, configured per table and used without code; memoising anything else, such as the SCARR rows or cl_salv_table references in the examples of [ABAP-CACHE-BOX](https://github.com/furkancosgun/ABAP-CACHE-BOX), is written into the program."},"cap":{"description":"Caching in CAP can mean HTTP response validation, retaining the result of a query or function, or querying a replicated copy of service data. The core, application plugins and a backing store answer different parts of that concern. HTTP response caching, query-result caching, remote-service response caching and application-level memoisation are different choices; stale-data behaviour and tenant isolation need to be considered for the chosen layer."}},"drafted_with_ai":true,"facets":[{"key":"cache_layer","label":"Caching layer","kind":"text","ecosystems":["cap"]},{"key":"freshness_control","label":"Freshness control","kind":"text","ecosystems":["cap"]},{"key":"tenant_partitioning","label":"Tenant partitioning","kind":"text","ecosystems":["cap"]}]},"sap_delivery":{"door":"cap","all":{"built_in":[{"ref":"artifact:sap-cds","name":"@sap/cds","json":"/artifacts/sap-cds.json"}],"documented_pattern":[],"announced":[],"packages":[]},"by_flavor":{"node":{"built_in":[{"ref":"artifact:sap-cds","name":"@sap/cds","json":"/artifacts/sap-cds.json"}],"documented_pattern":[],"announced":[],"packages":[]},"java":null}},"edges":{"use_cases":[{"id":"cache-a-remote-service-response-in-a-cap-application","name":"Cache a remote service response","capability":"capability:caching","ecosystem":"cap","flavors":["node"],"outcome":"A read that would call out to a remote service on every request is answered from a retained response until it expires.","boundary":"Covers a response from a service the application calls out to. Retaining the result of a local query is a separate task, and so is copying the remote data into a local database and querying that.","origin":"Editorial hypothesis, from the remote-service read-through call in the cds-caching documentation and the two cache strategies in the cds-data-federation documentation.","requirement_dimensions":["Whether the call is written by hand or declared on a federated entity","How old a response may be before the application calls out again","Whether the response varies per user or per locale","Whether the federated entity is read-only or writable"],"contributions":[{"ref":"artifact:cds-caching","role":"result cache","state":"documented","version_scope":"README at mikezaschka/cds-caching commit 2ad749c.","description":"cache.rt.send takes the request and the remote service and returns the retained response with the ttl the call states. The call is written where the application would otherwise send to the service.","remaining_work":"Choose the ttl and call the cache instead of the service. The plugin documents the call, not which reads are worth retaining.","sources":[{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Read-Through Caching for remote services","checked":"2026-09-19","quote":"const { result } = await cache.rt.send(request, remoteService, { ttl: 10000 })"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — README","checked":"2026-09-19","quote":"Transparently cache CQN queries, CAP requests, or function calls"}]},{"ref":"artifact:mikezaschka-cds-data-federation","role":"federated read adapter","state":"conditional","conditions":["cache.strategy is left at its default of response","cds-caching is installed, which the page names as an optional peer dependency"],"description":"On a delegated entity the response strategy routes the federated read through cds-caching, so the retaining is declared on the consumption view rather than written into a handler. The entity strategy answers a different shape of the same wish: it stores a snapshot of the remote projection in secondary SQLite and serves reads from there until the ttl runs out.","remaining_work":"Install the peer dependency and annotate the view. The strategy selects a cache, it is not a second one; the entity strategy brings cds-data-pipeline and @cap-js/sqlite with it.","remaining_kinds":["configuration"],"sources":[{"url":"https://mikezaschka.github.io/cds-data/federation/integration/caching.html","title":"cds-data-federation — Caching Federated Entities, response strategy","checked":"2026-09-19","quote":"cache.strategy: 'response' (default) — provided by cds-caching, an optional peer dependency."},{"url":"https://mikezaschka.github.io/cds-data/federation/integration/caching.html","title":"cds-data-federation — Caching Federated Entities, entity strategy","checked":"2026-09-19","quote":"stores a full remote projection snapshot in secondary SQLite via cds-data-pipeline, then satisfies arbitrary READ CQNs from SQLite until TTL."},{"url":"https://mikezaschka.github.io/cds-data/federation/integration/caching.html","title":"cds-data-federation — Caching Federated Entities, packages","checked":"2026-09-19","quote":"npm add cds-data-pipeline @cap-js/sqlite"}]},{"ref":"artifact:sap-cds","role":"core runtime","state":"unknown","description":"Whether the CAP Node.js runtime retains a remote service response is not established here. Capire's CAP-level Service Integration guide, read on 2026-09-19, covers importing an API, integrating the model and writing the integration logic, and does not mention caching.","remaining_work":"Read the remote services and destinations documentation on capire before treating this as settled. Absence from the integration guide is not a statement that the runtime does nothing."}],"readings":[{"ref":"content:federating-replicating-and-caching-remote-data-in-cap-part-1","relevance":"Fixes the vocabulary this task sits in: delegation forwards each request to the remote at query time, replication is a scheduled copy, and caching is an option on either rather than a third strategy. Written by the maintainer of the plugins it describes.","flavors":["node"]},{"ref":"content:federating-replicating-and-caching-remote-data-in-cap-part-2","relevance":"The walkthrough half: one application that federates, replicates and caches remote data, step by step, with the finished project published.","flavors":["node"]}],"unknowns":["Whether a response retained through the federation adapter carries the same user and locale key awareness as a direct cds-caching call is not stated on the federation caching page read here.","No capire page documenting the core's behaviour for remote service calls was located for this assessment. Two guessed URLs returned 404 on 2026-09-19."],"assessed_at":"2026-09-19","drafted_with_ai":true,"omitted_contributions":0,"assessment_kind":"documented-contributions"},{"id":"cache-the-result-of-a-function-call-in-a-cap-service","name":"Cache the result of a function call","capability":"capability:caching","ecosystem":"cap","flavors":["node"],"outcome":"A function the application would otherwise run on every call returns a value retained from an earlier call until it expires.","boundary":"Covers retaining what a function returns, under a key that carries the arguments it was called with. Retaining the result of a query and retaining a response from a remote service are separate tasks, and so is where the retained value is kept.","origin":"Editorial hypothesis. Function calls are the third of the three things the cds-caching README names it retains, and the corpus already holds a task for the query and one for the remote request.","requirement_dimensions":["Whether the function is declared in the CDS model or is plain application code","Whether the same arguments always produce the same value","How old a returned value may be","Whether the value varies per user, tenant or locale"],"contributions":[{"ref":"artifact:cds-caching","role":"result cache","state":"documented","version_scope":"README and docs/key-management.md at mikezaschka/cds-caching commit 2ad749c.","description":"Two routes to the same outcome. A @cache annotation on a function in the CDS model retains what it returns for the ttl it states, so the decision sits on the declaration. In code, cache.rt.wrap takes a name and the function and hands back a cached version of it, and cache.rt.exec runs a function once with its arguments and retains what came back. The arguments are part of the generated key, so a call with different arguments is held separately.","remaining_work":"Name the function and choose the ttl. Whether a function returns the same value for the same arguments stays the application's to decide: the pages read here document the key and the expiry, not which functions are worth retaining or safe to retain.","remaining_kinds":["configuration"],"sources":[{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — README","checked":"2026-09-27","quote":"Transparently cache CQN queries, CAP requests, or function calls"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Annotation-Based Caching, function","checked":"2026-09-27","quote":"@cache: { ttl: 60000 }\nfunction getRecommendations() returns array of Products;"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Read-Through Caching, wrapped function","checked":"2026-09-27","quote":"const cachedFn = cache.rt.wrap(\"bp-data\", fetchBPData, { ttl: 3600, tags: ['bp'] })"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Read-Through Caching, one-off execution","checked":"2026-09-27","quote":"const { result } = await cache.rt.exec(\"product\", fetchProduct, [\"1000001\"], { ttl: 3600 })"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/docs/key-management.md","title":"cds-caching — Key management, wrapped functions","checked":"2026-09-27","quote":"For wrapped functions, the cache key is generated based on function arguments and global context:"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/docs/key-management.md","title":"cds-caching — Key management, default template","checked":"2026-09-27","quote":"**Default template:** `{baseKey}:{args[0]}:{args[1]}:...:{args[n]}` (if no global context enabled)"}]},{"ref":"artifact:sap-cds","role":"core runtime","state":"unknown","description":"Whether the CAP Node.js runtime retains what a function returns is not established here. No capire page documenting a result cache for a function or an action was located for this assessment.","remaining_work":"Read the Node.js runtime and performance documentation on capire before treating this as settled. Nothing read here states that the runtime does this, and nothing read here states that it does not."}],"unknowns":["The key-management page states that global context is prepended to the function template. Which of user, tenant and locale is on by default for a function cache in particular was not established from the pages read here.","The plugin's introduction post, already attached to this capability, returned HTTP 403 on 2026-09-27, so no reading was checked for whether it shows a function cache working.","Only cds-caching was assessed for this outcome. The other CAP providers on this capability document copying a service and caching a federated entity read, which are a different shape, and this record does not assess either of them for a function result."],"assessed_at":"2026-09-27","drafted_with_ai":true,"readings":[],"omitted_contributions":0,"assessment_kind":"documented-contributions"},{"id":"keep-a-cached-result-from-reaching-the-wrong-tenant-user-or-locale","name":"Keep a cached result from reaching the wrong tenant, user or locale","capability":"capability:caching","ecosystem":"cap","flavors":["node"],"outcome":"A result retained for one tenant, one user or one language is not returned to a request that belongs to another.","boundary":"Covers the key a retained entry is held under and where the store keeps it. Tenant isolation of the application's own data, and the subscription mechanics themselves, belong to multitenancy and are assessed there. Nothing here establishes that a leak was observed or ruled out in any application.","origin":"Editorial hypothesis, from three dimensions with three different defaults in the same plugin's security guide, and a replication option that states it is not tenant aware.","requirement_dimensions":["Whether the application runs with multitenancy","Whether a handler filters or enriches a result per user after the query has run","Whether responses carry translated texts","Which store holds the entries"],"contributions":[{"ref":"artifact:cds-caching","role":"key isolation","state":"conditional","version_scope":"README and docs/security.md at mikezaschka/cds-caching commit 2ad749c.","conditions":["Multitenancy is detected, which is what turns tenant-aware keys on, and the opt-out is not set","User awareness is set for caches whose responses vary per user without the query varying","Locale awareness is set for caches holding translated texts"],"description":"Tenant, user and locale are three separate dimensions of the cache key with three different defaults. Tenant awareness turns itself on when multitenancy is detected. User awareness is the application's to set, because a result a handler filters after the query has run carries the same key for every caller. Locale is off, so responses in different languages share one entry until it is switched on. Where the entries sit follows the store: with the cds store each tenant's cache data is held in that tenant's own HDI container.","remaining_work":"Decide per cache which dimensions belong in the key and set the ones that do not default. The plugin documents the switches, not which of an application's responses vary by user or language.","sources":[{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Multi-tenancy, tenant-aware keys","checked":"2026-09-19","quote":"`isTenantAware` is automatically set to `true` in MTX mode."},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/docs/security.md","title":"cds-caching — Tenant and user isolation, tenant default","checked":"2026-09-19","quote":"so tenants are separated by default in MTX mode."},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/docs/security.md","title":"cds-caching — Tenant and user isolation, responses that vary by user","checked":"2026-09-19","quote":"the query is identical for every caller and so is the key"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/docs/security.md","title":"cds-caching — Tenant and user isolation, locale","checked":"2026-09-19","quote":"so responses in different languages share one entry"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Multi-tenancy, cds store","checked":"2026-09-19","quote":"With `store: 'cds'`, each tenant's cache data lives in its own HDI container"}]},{"ref":"artifact:cap-js-community-common","role":"service replica","state":"conditional","version_scope":"README at cap-js-community/common commit e1abccc.","conditions":["The entity is not annotated for static replication, which the README states is not tenant aware"],"description":"The replica is held in a tenant-aware SQLite database, so each tenant queries its own copy. One annotation opts out of that: static replication is stated as non-tenant aware, which is the arrangement for rows that are the same for everyone.","remaining_work":"Check every entity annotated for static replication for whether its rows really are the same for all tenants. User and locale are not dimensions this section names at all.","sources":[{"url":"https://raw.githubusercontent.com/cap-js-community/common/e1abccca5c67218ec548150b9c183e229d5b2419/README.md","title":"CAP Node.js Community Common — Replication Cache","checked":"2026-09-19","quote":"The replication cache allows to cache a service (e.g. db service) into a tenant-aware SQLite database."},{"url":"https://raw.githubusercontent.com/cap-js-community/common/e1abccca5c67218ec548150b9c183e229d5b2419/README.md","title":"CAP Node.js Community Common — Replication Cache, static replication","checked":"2026-09-19","quote":"`@cds.replicate.static: Boolean`: Statically replicate non-tenant aware"}]}],"unknowns":["Whether entries written before user or locale awareness was switched on are dropped or kept is not stated in the guide read here.","Nothing read here states what happens to keys already held in a shared Redis store when a tenant is offboarded.","Whether a response retained through cds-data-federation carries the same key dimensions as a direct cds-caching call is not stated on the federation caching page."],"assessed_at":"2026-09-19","drafted_with_ai":true,"readings":[],"omitted_contributions":0,"assessment_kind":"documented-contributions"},{"id":"refresh-a-cached-read-after-a-write-in-cap","name":"Refresh cached reads after a write","capability":"capability:caching","ecosystem":"cap","flavors":["node"],"outcome":"A read answered from a cache reflects a write to the underlying data within a bound the application sets.","boundary":"Covers what clears or ages out a retained result. Which reads are retained, and where they are kept, are separate tasks.","origin":"Editorial hypothesis. The three CAP providers on this capability document invalidation differently, which is the decision the task exposes.","requirement_dimensions":["Whether the cached data is written through the same application","How long a read may keep returning the value from before the write","Whether the retained shape is a projection of one entity or a result assembled from several keys"],"contributions":[{"ref":"artifact:cds-caching","role":"result cache","state":"documented","version_scope":"README at mikezaschka/cds-caching commit 2ad749c.","description":"invalidateOnWrite clears the cached queries for an entity when its data changes, registered as after handlers for CREATE, UPDATE and DELETE. Tags are the other route: keys set under a tag are cleared together by deleteByTag, which is how a write can clear a result assembled from several keys.","remaining_work":"Set the flag per entity, or assign tags and call deleteByTag from the handler that writes. A write that reaches the data by another route is not covered by either.","remaining_kinds":["configuration","application-code"],"sources":[{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Automatic Invalidation on Write","checked":"2026-09-19","quote":"For annotation-based entity caching, use `invalidateOnWrite` to automatically clear all cached queries for an entity whenever its data changes"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Automatic Invalidation on Write, handlers","checked":"2026-09-19","quote":"This registers `after` handlers for CREATE, UPDATE, and DELETE that call `deleteByTag` with an entity-level tag. All cached variants (filtered, sorted, paginated, single-entity) are invalidated at once."},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Tag-based invalidation","checked":"2026-09-19","quote":"await cache.deleteByTag(\"bp-list\")"}]},{"ref":"artifact:mikezaschka-cds-data-federation","role":"federated read adapter","state":"explicitly-unsupported","description":"Automatic clearing on a write. A write through a writable delegate does not clear the cache under either strategy, and the documentation records that as a stated behaviour with the alternative named.","remaining_work":"Clear the entry from the write path, or shorten the ttl so the window is the staleness the application accepts.","remaining_kinds":["configuration","application-code"],"sources":[{"url":"https://mikezaschka.github.io/cds-data/federation/integration/caching.html","title":"cds-data-federation — Caching Federated Entities, writable delegates","checked":"2026-09-19","quote":"For writable delegates, neither cache strategy auto-invalidates on CUD — plan manual invalidation or shorter TTL."}]},{"ref":"artifact:cap-js-community-common","role":"service replica","state":"documented","version_scope":"README at cap-js-community/common commit e1abccc.","description":"The replica ages out on a time to live given in milliseconds, and the same annotation block carries auto and preload for when the copy is made. Time is the bound this section states.","remaining_work":"Set the ttl per entity. Whether a write through the replicated service clears its copy is not stated in the section read here, so the ttl is the only bound this assessment records.","remaining_kinds":["configuration"],"sources":[{"url":"https://raw.githubusercontent.com/cap-js-community/common/e1abccca5c67218ec548150b9c183e229d5b2419/README.md","title":"CAP Node.js Community Common — Replication Cache annotations","checked":"2026-09-19","quote":"`@cds.replicate.ttl: Number`: Time-To-Live (TTL) of cache entry in milliseconds"},{"url":"https://raw.githubusercontent.com/cap-js-community/common/e1abccca5c67218ec548150b9c183e229d5b2419/README.md","title":"CAP Node.js Community Common — Replication Cache, automatic replication","checked":"2026-09-19","quote":"`@cds.replicate.auto: Boolean`: Replication is managed automatically"}]}],"unknowns":["Whether a write through the replicated service clears its replica is not stated in the replication cache section read on 2026-09-19. Absence in that section is not a statement that it does not happen.","invalidateOnWrite is documented for annotation-based entity caching. Whether a result retained through the read-through calls is cleared the same way is not stated in the lines read here.","Nothing read here states what clears a cached result when the underlying data is changed outside the application, by another consumer of the same database or remote system."],"assessed_at":"2026-09-19","drafted_with_ai":true,"readings":[],"omitted_contributions":0,"assessment_kind":"documented-contributions"},{"id":"serve-repeated-reads-from-a-cache-in-a-cap-service","name":"Serve repeated reads of a rarely written entity from a cache","capability":"capability:caching","ecosystem":"cap","flavors":["node"],"outcome":"Reads of an entity that is read constantly and written rarely are answered inside the application instead of going to the database on every request.","boundary":"Covers retaining the result of a read. Keeping it fresh after a write is a separate task, and so is where the retained result is kept.","origin":"Editorial hypothesis. The read-heavy shape is taken from a practitioner account already attached to this capability.","requirement_dimensions":["How often the entity is written against how often it is read","How old an answer may be","Whether the same read has to be answered by more than one application instance"],"contributions":[{"ref":"artifact:cds-caching","role":"result cache","state":"documented","version_scope":"README at mikezaschka/cds-caching commit 2ad749c.","description":"A @cache annotation on a service entity retains the results of reads on it for the ttl it states, and it sits on the projection rather than in a handler. Where the decision belongs in code instead, cache.rt.run takes the query and the service and returns the result with the ttl the call states.","remaining_work":"Decide the ttl entity by entity. The annotation is per projection, so each one is its own decision, and nothing picks the entities worth retaining.","remaining_kinds":["configuration"],"sources":[{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Annotation-Based Caching","checked":"2026-09-19","quote":"@cache: { ttl: 10000 }\n  entity Products as projection on db.Products;"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Read-Through Caching for CQN queries","checked":"2026-09-19","quote":"const { result } = await cache.rt.run(query, db, { ttl: 30000 })"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — README","checked":"2026-09-19","quote":"Transparently cache CQN queries, CAP requests, or function calls"}]},{"ref":"artifact:cap-js-community-common","role":"service replica","state":"documented","version_scope":"README at cap-js-community/common commit e1abccc.","description":"Answers the same outcome by a different mechanism: it holds a copy of a service in SQLite and runs the original query against the copy, so the read shape in the application does not change. The README gives the db service as its example.","remaining_work":"Install @cap-js/sqlite as a dependency rather than a development dependency, and annotate the entities to replicate.","remaining_kinds":["configuration"],"sources":[{"url":"https://raw.githubusercontent.com/cap-js-community/common/e1abccca5c67218ec548150b9c183e229d5b2419/README.md","title":"CAP Node.js Community Common — Replication Cache","checked":"2026-09-19","quote":"The replication cache allows to cache a service (e.g. db service) into a tenant-aware SQLite database."},{"url":"https://raw.githubusercontent.com/cap-js-community/common/e1abccca5c67218ec548150b9c183e229d5b2419/README.md","title":"CAP Node.js Community Common — Replication Cache, local query","checked":"2026-09-19","quote":"Local replicated SQLite database can be queried with same query as the original service."},{"url":"https://raw.githubusercontent.com/cap-js-community/common/e1abccca5c67218ec548150b9c183e229d5b2419/README.md","title":"CAP Node.js Community Common — Replication Cache, prerequisite","checked":"2026-09-19","quote":"Ensure `@cap-js/sqlite` is installed as dependency (not as dev dependency) in your project."}]},{"ref":"artifact:sap-cds","role":"core runtime","state":"unknown","description":"Whether the CAP Node.js runtime holds a query result between requests is not established by the pages read for this assessment. Capire's generic service providers page documents ETag validation, which answers a conditional request rather than retaining a result, and the service integration guide read on 2026-09-19 does not mention caching at all.","remaining_work":"Read the CAP Node.js databases and performance documentation before treating this as settled. Two guessed capire URLs for a performance guide returned 404 on 2026-09-19, so the page that would answer it was not located."}],"readings":[{"ref":"content:performance-boost-and-caching-strategy-with-cds-caching","relevance":"Somebody else's account of exactly this shape: a master-data entity of more than a million rows, rarely written and constantly read, and what integrating the plugin changed in that application.","flavors":["node"]},{"ref":"content:boosting-performance-in-cap-with-cds-caching","relevance":"The plugin's own introduction post, on the cases it was written against. Its call sites predate version 1.0 and show the read-through calls the README now lists as deprecated.","flavors":["node"]}],"unknowns":["The replication cache section names a service and gives the db service as its example. Which other services can be replicated is not stated there, so this assessment does not record it for a remote service.","Nothing read here states what happens to entries held in the default memory store when an application instance restarts."],"assessed_at":"2026-09-19","drafted_with_ai":true,"omitted_contributions":0,"assessment_kind":"documented-contributions"},{"id":"share-one-cache-across-cap-application-instances","name":"Share one cache across application instances","capability":"capability:caching","ecosystem":"cap","flavors":["node"],"outcome":"Several instances of the same application read and write one cache, so a result retained while serving one request answers a later request routed to a different instance.","boundary":"Covers where a retained result is kept. What is retained, and when it expires, are separate tasks. Whether a subaccount may provision a given service plan is a project question and is not assessed here.","origin":"Editorial hypothesis, from the store table in the cds-caching documentation and the Redis plans in SAP's BTP service metadata.","requirement_dimensions":["How many application instances serve the same requests","Whether the subaccount is entitled to a Redis plan","Whether the application database is SAP HANA, which the cds store reuses","Whether the application is multitenant"],"paths":[{"key":"redis-store","name":"With the redis store on Redis on SAP BTP","sources":[{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/docs/deployment-guide.md","title":"cds-caching — Redis on SAP BTP","checked":"2026-09-23","quote":"Redis can be provisioned as a managed service through the Redis on SAP BTP hyperscaler option."}]}],"contributions":[{"ref":"artifact:cds-caching","role":"result cache","state":"conditional","paths":["redis-store"],"version_scope":"README at mikezaschka/cds-caching commit 2ad749c.","conditions":["A store other than the default memory store is configured","The adapter package the store table names for that store is installed"],"description":"The store is configuration rather than code. The table names memory for development and small scale, sqlite for a single instance, redis for production and distributed use, postgres, a direct hana connection, and a cds store that uses the application's own database. Under multitenancy the README states what each of the two production shapes does with tenants: the cds store puts each tenant's cache data in its own HDI container, and the redis store prefixes keys with the tenant.","remaining_work":"Set the store, install its adapter package and bind the backing service. Memory is what is configured until then.","remaining_kinds":["configuration"],"sources":[{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Store Types, Redis","checked":"2026-09-19","quote":"| Redis | `\"redis\"` | Production, distributed | `@keyv/redis` |"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Store Types, CDS database","checked":"2026-09-19","quote":"| CDS Database | `\"cds\"` | Production, HANA, multi-tenant | None (uses app's DB) |"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Configuration, default store","checked":"2026-09-19","quote":"| `store` | `\"memory\"` | Storage backend (`memory`, `sqlite`, `redis`, `postgres`, `hana`, `cds`) |"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Multi-tenancy, shared Redis","checked":"2026-09-19","quote":"Alternatively, use `store: 'redis'` for shared Redis with automatic tenant-prefixed keys:"},{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/README.md","title":"cds-caching — Multi-tenancy, cds store","checked":"2026-09-19","quote":"With `store: 'cds'`, each tenant's cache data lives in its own HDI container"}]},{"ref":"artifact:btp-redis","role":"managed store","state":"documented","paths":["redis-store"],"description":"The instance an application binds when the redis store is configured. The plugin's deployment guide provisions service redis-cache in the mta descriptor and tags the instance cds-caching; SAP's service metadata records the plans the service offers, from a free plan for non-productive development to a premium one.","remaining_work":"Provision an instance on a plan the subaccount is entitled to and bind it. Which plans a given subaccount may use is a project question, not a documented property of either the service or the plugin.","remaining_kinds":["configuration"],"sources":[{"url":"https://raw.githubusercontent.com/mikezaschka/cds-caching/2ad749c2b47186cb740efb61c8022d6a1bee8f9c/docs/deployment-guide.md","title":"cds-caching — Redis on SAP BTP","checked":"2026-09-19","quote":"Redis can be provisioned as a managed service through the Redis on SAP BTP hyperscaler option."},{"url":"https://raw.githubusercontent.com/SAP-samples/btp-service-metadata/main/v1/developer/redis-cache.json","title":"SAP BTP service metadata — Redis, hyperscaler option, premium plan","checked":"2026-09-19","quote":"Create production-ready Redis Cache instances with premium features."},{"url":"https://raw.githubusercontent.com/SAP-samples/btp-service-metadata/main/v1/developer/redis-cache.json","title":"SAP BTP service metadata — Redis, hyperscaler option, free plan","checked":"2026-09-19","quote":"Redis cache service for non-productive development usage"}]}],"unknowns":["PostgreSQL is named in the same store table and has no artifact entry, so it is not recorded as a contribution here. That is a limit of what the graph admits, not a statement about the store.","Whether an equivalent shared result cache is documented for CAP Java was not established. com.sap.cds:cds-feature-redis connects a messaging service to Redis Pub/Sub, which answers a different concern, and no Java page was read for this task.","Neither the store table nor the deployment guide read here states what happens to entries held in the memory store when an instance restarts, or how two instances behave while one of them still holds an entry the other has cleared."],"assessed_at":"2026-09-19","drafted_with_ai":true,"history":[{"date":"2026-09-23","field":"paths","from":null,"to":"redis-store","reason":"npm run check:usecases found the graph joins the two contributions by an edge while no path held them together. They are two parts of one way, the plugin's redis store on the managed Redis service, which the plugin's own deployment guide shows provisioned for it, quoted on the path."}],"readings":[],"omitted_contributions":0,"assessment_kind":"documented-contributions"},{"id":"skip-resending-a-record-the-client-already-has","name":"Skip resending a record the client already has","capability":"capability:caching","ecosystem":"cap","flavors":["node","java"],"outcome":"A client that re-reads an entity it has already fetched gets 304 and no body back when the record has not changed since.","boundary":"Covers a conditional read over HTTP on a served entity. Retaining a query, request or function result inside the application is a separate task, and so is telling a client how long it may reuse what it has without asking again.","origin":"Editorial hypothesis, drawn from the ETag support already recorded in this capability's CAP coverage.","requirement_dimensions":["Whether the entity carries an element that changes on every modification","Whether the client sends back the ETag it received","Runtime flavor"],"contributions":[{"ref":"artifact:sap-cds","role":"core runtime","state":"documented","flavors":["node"],"description":"A read carrying If-None-Match is answered with 304 and no body while the annotated element still matches. Capire's example is a GET on Employees/111 with the previous timestamp in the header.","remaining_work":"Annotate an element with @odata.etag. Capire annotates modifiedAt from the managed aspect, which changes on each modification, and the client has to send back what it received.","remaining_kinds":["configuration"],"sources":[{"url":"https://cap.cloud.sap/docs/guides/services/served-ootb","title":"capire — Concurrency Control","checked":"2026-09-19","quote":"The CAP runtimes support optimistic concurrency control and caching techniques using ETags."},{"url":"https://cap.cloud.sap/docs/guides/services/served-ootb","title":"capire — Concurrency Control, conditional read example","checked":"2026-09-19","quote":"304 Not Modified // Record was not changed"},{"url":"https://cap.cloud.sap/docs/guides/services/served-ootb","title":"capire — Concurrency Control, ETag annotation","checked":"2026-09-19","quote":"annotate Foo with { modifiedAt @odata.etag }"}]},{"ref":"artifact:cap-java-cds-services-bom","role":"core runtime","state":"documented","flavors":["java"],"description":"Capire states the support for the CAP runtimes rather than for one of them, and the annotation it shows is a CDS annotation on the model both runtimes compile.","remaining_work":"The same @odata.etag annotation. The page carries one example and no step specific to Java, so what a Java project does beyond the annotation is not stated there.","remaining_kinds":["configuration"],"sources":[{"url":"https://cap.cloud.sap/docs/guides/services/served-ootb","title":"capire — Concurrency Control","checked":"2026-09-19","quote":"The CAP runtimes support optimistic concurrency control and caching techniques using ETags."}]}],"unknowns":["Whether a 304 answer skips the database read or only the payload is not stated on the capire page read here, so this assessment records the header behaviour and nothing about what the server still does.","The Java runtime is credited from a sentence that names both runtimes together. No Java-side page was read for this task, and https://cap.cloud.sap/docs/java/event-handlers/etags returned 404 on 2026-09-19."],"assessed_at":"2026-09-19","drafted_with_ai":true,"readings":[],"omitted_contributions":0,"assessment_kind":"documented-contributions"},{"id":"tell-a-client-how-long-a-served-file-stays-fresh","name":"Tell a client how long a served file stays fresh","capability":"capability:caching","ecosystem":"cap","flavors":["node","java"],"outcome":"A client that has fetched a file served by the application keeps using it for a stated number of seconds without asking the application again.","boundary":"Covers the freshness window the application sends with a response. Answering a conditional request with 304, which still costs a round trip, is a separate task, and so is retaining a result inside the application.","origin":"Editorial hypothesis, from the Java-only Cache Control sentence already recorded in this capability's CAP coverage.","requirement_dimensions":["Runtime flavor","Whether what is served is a stream property or an ordinary entity read","How long a client may keep using a file that has since changed","Whether anything between the client and the application holds the response as well"],"contributions":[{"ref":"artifact:cap-java-cds-services-bom","role":"core runtime","state":"documented","flavors":["java"],"description":"An annotation in the CDS model, @http.CacheControl with a maxAge in seconds on a stream property, sets the Cache-Control header on the response. The page states that max-age counts from when the response was generated on the origin server rather than from when the client received it, so the window a client sees can be shorter than the number in the model.","remaining_work":"Annotate the stream property and pick the number of seconds. Nothing recalls a response already sent, so the number is the longest a client may serve content that has since changed.","remaining_kinds":["configuration"],"sources":[{"url":"https://cap.cloud.sap/docs/guides/uis/fiori","title":"capire — Cache Control in Java, annotation","checked":"2026-09-19","quote":"In the CDS model, use the `@http.CacheControl: {maxAge: <seconds>}` annotation on stream properties."},{"url":"https://cap.cloud.sap/docs/guides/uis/fiori","title":"capire — Cache Control in Java, elapsed time","checked":"2026-09-19","quote":"max-age is the elapsed time since the response was generated on the origin server, not the time since the response was received."}]},{"ref":"artifact:sap-cds","role":"core runtime","state":"explicitly-unsupported","flavors":["node"],"description":"Capire scopes the Cache Control feature to the Java runtime, so the same annotation is not documented as doing anything on Node.js.","remaining_work":"Set the header from the application's own code, or take one of the other mechanisms this capability records. The page does not state what a Node.js runtime does with @http.CacheControl when the annotation is in the model.","remaining_kinds":["configuration","application-code"],"sources":[{"url":"https://cap.cloud.sap/docs/guides/uis/fiori","title":"capire — Cache Control in Java, runtime scope","checked":"2026-09-19","quote":"The Cache Control feature is currently supported only on the Java runtime."}]}],"unknowns":["Whether the annotation applies to anything other than a stream property is not stated on the page read here.","Nothing read here states how a client is brought back early when the file changes inside the window it was given."],"assessed_at":"2026-09-19","drafted_with_ai":true,"readings":[],"omitted_contributions":0,"assessment_kind":"documented-contributions"}],"shared_tasks":[],"related_tasks":[],"options":[{"ref":"artifact:cap-js-community-common","name":"@cap-js-community/common","json":"/artifacts/cap-js-community-common.json","ecosystem":"cap","origin_ring":"community-org"},{"ref":"artifact:sap-cds","name":"@sap/cds","json":"/artifacts/sap-cds.json","ecosystem":"cap","origin_ring":"sap-official"},{"ref":"artifact:furkancosgun-abap-cache-box","name":"ABAP-CACHE-BOX","json":"/artifacts/furkancosgun-abap-cache-box.json","ecosystem":"abap","origin_ring":"independent"},{"ref":"artifact:cds-caching","name":"cds-caching","json":"/artifacts/cds-caching.json","ecosystem":"cap","origin_ring":"independent"},{"ref":"artifact:mikezaschka-cds-data-federation","name":"cds-data-federation","json":"/artifacts/mikezaschka-cds-data-federation.json","ecosystem":"cap","origin_ring":"independent"},{"ref":"artifact:btp-redis","name":"Redis on SAP BTP, hyperscaler option","json":"/artifacts/btp-redis.json","ecosystem":"btp","origin_ring":"sap-official"}],"samples":[],"explained_by":[{"ref":"content:performance-boost-and-caching-strategy-with-cds-caching","name":"Performance Boost and Caching Strategy for Faster Data Access using \"cds-caching\" in SAP CAP","json":"/content/performance-boost-and-caching-strategy-with-cds-caching.json"}],"normative_context":[]}}