npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cds-caching

v1.3.2

Published

A caching plugin for SAP CAP applications

Readme

Welcome to cds-caching

npm version monthly downloads

Overview

A caching plugin for the SAP Cloud Application Programming Model (CAP) that improves performance by caching slow remote service calls, complex operations, and queries.

Please also read the introduction blog post: Boosting performance in SAP Cloud Application Programming Model (CAP) applications with cds-caching.

Key Features

  • Read-Through Caching – Transparently cache CQN queries, CAP requests, or function calls
  • Pluggable Storage – In-memory, SQLite, Redis, PostgreSQL, SAP HANA, or CDS database
  • Multi-Tenancy – Automatic tenant isolation for SAP BTP MTX deployments
  • TTL & Tag Support – Time-based expiry and tag-based invalidation
  • Compression – LZ4 or GZIP compression for cached data
  • Metrics & Monitoring – Hit rates, latencies, key-level tracking, and an OData API
  • Annotations – Declarative caching via @cache annotations on entities and functions

Documentation

| Guide | Description | |-------|-------------| | Programmatic API | Full API reference for cache operations | | Key Management | Key templates, context awareness, custom keys | | Metrics Guide | Statistics, monitoring, and performance tracking | | OpenTelemetry Integration | Distributed tracing and metrics export | | OData API | REST endpoints for management and monitoring | | Dashboard | Setup and usage of the monitoring dashboard | | Deployment Guide | SAP BTP deployment for Redis, PostgreSQL, HANA, CDS | | Migration Guide | Upgrading from 0.x to 1.x, 1.1 to 1.2, and 1.2.x to 1.3.0 | | Example Application | Sample app with caching patterns |

Getting Started

Installation

npm install cds-caching

Minimal Configuration

{
  "cds": {
    "requires": {
      "caching": {
        "impl": "cds-caching"
      }
    }
  }
}

This uses the in-memory store — no additional setup needed for development.

Data Model

The plugin ships CDS entity definitions for database-backed features. These are auto-loaded conditionally based on your configuration — no manual model property or using from needed:

| Condition | Entities loaded | Purpose | |-----------|----------------|---------| | statistics block present | Caches, Metrics, KeyMetrics | Persist metrics and runtime config to the database | | store: 'cds' | CacheStore | Key-value table used by the CDS store adapter | | using from 'cds-caching/index.cds' | CachingApiService + statistics entities | OData API for the dashboard | | None of the above | Nothing | Plugin works with external stores only |

The auto-loading works by injecting the relevant CDS files into cds.env.roots at plugin load time, before CAP compiles the model. This means cds deploy and cds build automatically pick up the required tables.

Basic Usage

const cache = await cds.connect.to("caching")

// Key-value operations
await cache.set("bp:1000001", businessPartnerData, { ttl: 60000 })
const data = await cache.get("bp:1000001")

// Read-through caching for CQN queries
const { result } = await cache.rt.run(query, db, { ttl: 30000 })

// Read-through caching for remote services
const { result } = await cache.rt.send(request, remoteService, { ttl: 10000 })

// Function caching
const cachedFn = cache.rt.wrap("expensive-op", expensiveFunction, { ttl: 3600 })
const { result } = await cachedFn("param1")

Annotation-Based Caching

service MyService {
  @cache: { ttl: 10000 }
  entity Products as projection on db.Products;

  @cache: { ttl: 10000, invalidateOnWrite: true }
  entity Orders as projection on db.Orders;

  @cache: { ttl: 60000 }
  function getRecommendations() returns array of Products;
}

When invalidateOnWrite is set, the cache for that entity is automatically cleared after any CREATE, UPDATE, or DELETE operation, so subsequent reads always return fresh data.

Configuration

Store Types

| Store | Config | Use Case | Adapter Package | |-------|--------|----------|-----------------| | In-Memory | "memory" | Development, small-scale | Built-in | | SQLite | "sqlite" | Medium-size, single instance | @resolid/keyv-sqlite or @keyv/sqlite | | Redis | "redis" | Production, distributed | @keyv/redis | | PostgreSQL | "postgres" | Production, when Redis unavailable | @keyv/postgres | | CDS Database | "cds" | Production, HANA, multi-tenant | None (uses app's DB) | | SAP HANA | "hana" | Direct HANA connection | keyv-hana |

Recommendation: Use store: 'cds' for CAP applications on SAP HANA — it reuses your app's DB connection, requires no extra packages, and supports multi-tenancy automatically. Use store: 'redis' for best performance in distributed setups.

Full Configuration Options

{
  "cds": {
    "requires": {
      "caching": {
        "impl": "cds-caching",
        "namespace": "caching",
        "store": "redis",
        "compression": "lz4",
        "throwOnErrors": false,
        "transactionalOperations": false,
        "credentials": { },
        "statistics": {
          "enabled": true,
          "persistenceInterval": 60000
        },
        "keyManagement": {
          "isUserAware": false,
          "isTenantAware": false,
          "isLocaleAware": false
        }
      }
    }
  }
}

| Option | Default | Description | |--------|---------|-------------| | store | "memory" | Storage backend (memory, sqlite, redis, postgres, hana, cds) | | namespace | service name | Key prefix for store isolation | | compression | none | "lz4" or "gzip" | | throwOnErrors | false | Whether basic operations throw on cache errors | | transactionalOperations | false | Isolate basic ops in dedicated cache transactions | | statistics | none | When present, auto-loads the statistics data model and enables persistence (see Statistics & Monitoring) | | statistics.enabled | false | Enable metrics collection | | statistics.persistenceInterval | 60000 | Interval (ms) for persisting hourly stats to the database | | keyManagement.isTenantAware | false (auto true in MTX) | Include tenant in cache keys | | keyManagement.isUserAware | false | Include user in cache keys | | keyManagement.isLocaleAware | false | Include locale in cache keys |

Environment-Specific Configuration

{
  "cds": {
    "requires": {
      "caching": {
        "impl": "cds-caching",
        "store": "redis",
        "[development]": {
          "credentials": { "host": "localhost", "port": 6379 }
        },
        "[production]": {
          "credentials": { "url": "redis://production-redis:6379" }
        }
      }
    }
  }
}

For detailed key configuration and deployment instructions, see Key Management and Deployment Guide.

Service Integration

The plugin includes CachingApiService, an OData service for managing caches, browsing entries, and viewing metrics. It powers the dashboard and can be consumed by any OData client.

The easiest way to set this up is cds add caching-dashboard, which creates both the service exposure and the dashboard UI. To expose only the service without the dashboard, reference it in one of your .cds files:

using {plugin.cds_caching.CachingApiService} from 'cds-caching/index.cds';

annotate CachingApiService with @requires: 'authenticated-user';

This automatically loads the required database entities (Caches, Metrics, KeyMetrics) via a transitive using from dependency — no additional configuration needed. Without this step, the service won't be served by CAP and the dashboard won't work.

Multi-Tenancy (MTX)

cds-caching supports SAP BTP multi-tenant applications using @sap/cds-mtxs. When multitenancy is detected, the plugin automatically:

  • Enables tenant-aware cache keys ({tenant}:{hash})
  • Defers database operations to request-time (avoids startup crashes without tenant context)
  • Guards statistics persistence to only run within a tenant request context

Recommended Setup

{
  "cds": {
    "requires": {
      "multitenancy": true,
      "caching": {
        "impl": "cds-caching",
        "store": "cds"
      }
    }
  }
}

With store: 'cds', each tenant's cache data lives in its own HDI container — fully isolated by CAP's Service Manager.

Alternatively, use store: 'redis' for shared Redis with automatic tenant-prefixed keys:

{
  "cds": {
    "requires": {
      "multitenancy": true,
      "caching": {
        "impl": "cds-caching",
        "store": "redis",
        "credentials": { "socket": { "host": "localhost", "port": 6379 } }
      }
    }
  }
}

isTenantAware is automatically set to true in MTX mode. Set "isTenantAware": false in keyManagement to explicitly opt out.

Usage Patterns

Deprecation Notice: cache.run(), cache.send(), cache.wrap(), cache.exec() are deprecated since v1.0. Use cache.rt.run(), cache.rt.send(), cache.rt.wrap(), cache.rt.exec() instead. See Migration Guide.

Read-Through Query Caching

const { result } = await cache.rt.run(
  SELECT.from(BusinessPartners).where({ type: '2' }), 
  db, 
  { ttl: 30000 }
)

Read-Through Remote Service Caching

this.on('READ', BusinessPartners, async (req, next) => {
  const bupa = await cds.connect.to('API_BUSINESS_PARTNER')
  const { result } = await cache.rt.run(req, bupa, { ttl: 30000 })
  return result
})

ApplicationService Caching with prepend

this.prepend(() => {
  this.on('READ', MyEntity, async (req, next) => {
    const cache = await cds.connect.to("caching")
    const { result } = await cache.rt.run(req, next)
    return result
  })
})

Function Caching

// Wrap: create a cached version of a function
const cachedFn = cache.rt.wrap("bp-data", fetchBPData, { ttl: 3600, tags: ['bp'] })
const { result } = await cachedFn("1000001", true)

// Exec: immediate one-off execution with caching
const { result } = await cache.rt.exec("product", fetchProduct, ["1000001"], { ttl: 3600 })

Cache Invalidation

// Time-based (TTL)
await cache.set("key", value, { ttl: 60000 })

// Key-based
await cache.delete("bp:1000001")

// Tag-based
await cache.set("bp:1000001", data, { tags: [{ value: "bp-list" }] })
await cache.set("bp:1000002", data, { tags: [{ value: "bp-list" }] })
await cache.deleteByTag("bp-list")

// Dynamic tags from data
await cache.set("bp-list", bpArray, { 
  tags: [{ data: "businessPartner", prefix: "bp-" }] 
})

Automatic Invalidation on Write

For annotation-based entity caching, use invalidateOnWrite to automatically clear all cached queries for an entity whenever its data changes:

@cache: { ttl: 10000, invalidateOnWrite: true }
entity CachedProducts as projection on db.Products;

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.

For more usage patterns, error handling details, and TypeScript support, see Programmatic API.

Statistics & Monitoring

To persist metrics to the database, add a statistics block to your configuration. This automatically loads the required data model (Caches, Metrics, KeyMetrics tables):

{
  "cds": {
    "requires": {
      "caching": {
        "impl": "cds-caching",
        "store": "redis",
        "statistics": {
          "enabled": true,
          "persistenceInterval": 60000
        }
      }
    }
  }
}

You can also enable metrics at runtime:

const cache = await cds.connect.to("caching")
await cache.setMetricsEnabled(true)
await cache.setKeyMetricsEnabled(true)

const stats = await cache.getCurrentMetrics()

To add the monitoring dashboard to your project, run:

cds add caching-dashboard

This copies a pre-built UI5 dashboard into your app/ folder and exposes the CachingApiService. After running cds watch, the dashboard is available at /caching-dashboard/index.html.

Cache Dashboard

See the Dashboard Guide for details on features, security, and customization.

See the full Metrics Guide →

API Reference

| API | Description | |-----|-------------| | Programmatic API | JavaScript methods for cache operations | | OData API | REST endpoints for monitoring and management |

Contributing

Contributions are welcome! Please submit pull requests to the repository.

License

This project is licensed under the MIT License - see the LICENSE file for details.