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

@fluojs/cache-manager

v1.0.3

Published

Decorator-driven HTTP response caching and standalone cache service for Fluo, with memory and Redis backends.

Downloads

1,453

Readme

@fluojs/cache-manager

General-purpose cache manager for fluo with pluggable memory, Redis, and custom store adapters. Provides both decorator-driven HTTP response caching and a standalone cache API for application-level caching.

Table of Contents

Installation

npm install @fluojs/cache-manager

The root @fluojs/cache-manager import stays safe for memory-only installs. You only need Redis peers when you explicitly select the Redis-backed store path.

For Redis-backed caching:

npm install @fluojs/cache-manager @fluojs/redis ioredis

When to Use

  • When you want to cache expensive database queries or external API responses.
  • When you need to improve HTTP performance by caching GET responses.
  • When you need to share cache state across multiple instances (using Redis).
  • When you need a simple "remember" pattern (fetch if missing, then cache).

Quick Start

HTTP Response Caching

Register the CacheModule and use the CacheInterceptor on your controllers.

The built-in memory path is intentionally bounded by default: when you omit ttl, fluo applies a 300-second default TTL and keeps at most 1,000 live memory-store entries before evicting the oldest keys.

import { Module } from '@fluojs/core';
import { Controller, Get, UseInterceptors } from '@fluojs/http';
import { CacheModule, CacheInterceptor, CacheTTL } from '@fluojs/cache-manager';

@Controller('/products')
class ProductController {
  @Get('/')
  @UseInterceptors(CacheInterceptor)
  @CacheTTL(60) // Cache for 60 seconds
  list() {
    return [{ id: 1, name: 'Product A' }];
  }
}

@Module({
  imports: [CacheModule.forRoot({ store: 'memory' })],
  controllers: [ProductController],
})
class AppModule {}

Application-Level Caching

Inject CacheService to manage cache programmatically.

import { Inject } from '@fluojs/core';
import { CacheService } from '@fluojs/cache-manager';

@Inject(CacheService)
class UserService {
  constructor(private readonly cache: CacheService) {}

  async getProfile(userId: string) {
    return this.cache.remember(`user:${userId}`, async () => {
      // This runs only if the key is missing from cache
      return fetchUserProfile(userId);
    }, 300); // 5 minutes
  }
}

Common Patterns

Redis Storage

To use Redis, ensure @fluojs/redis is configured and set the store to 'redis'.

Memory-only consumers can keep importing from @fluojs/cache-manager without installing @fluojs/redis or ioredis; those optional peers are resolved only when the Redis store path is selected.

CacheModule.forRoot({
  store: 'redis',
  ttl: 600,
  keyPrefix: 'myapp:cache:',
})

If you registered multiple Redis clients, set redis.clientName to target a named @fluojs/redis connection.

Leave redis.clientName unset to keep using the default Redis client resolved through REDIS_CLIENT.

CacheModule.forRoot({
  store: 'redis',
  redis: { clientName: 'cache' },
})

redis.client remains the highest-precedence override. Use it only when you need to bypass DI-based client selection entirely.

The built-in RedisStore persists entries with JSON.stringify(...). Cache values therefore need to be JSON-compatible: plain objects, arrays, strings, numbers, booleans, and null round-trip cleanly, while values such as Date come back as JSON output (for example ISO strings), functions/undefined/symbols do not survive, and non-serializable values like bigint or cyclic graphs should be normalized before caching.

Positive Redis TTL values are accepted in seconds and may be fractional. Redis expiry is rounded up to the next whole second because Redis EX uses integer seconds, while fluo also records the millisecond-precision expiry timestamp in the stored entry and treats the value as expired once that timestamp is reached. Use ttl: 0 when you intentionally want no Redis expiry.

Redis reset ownership is scoped by the top-level keyPrefix option, which defaults to fluo:cache: and is passed through to the built-in RedisStore namespace. CacheService.reset() deletes only keys under that prefix for Redis-backed stores, so application-owned Redis data outside the cache prefix is preserved. If you intentionally configure an empty keyPrefix, reset is limited to keys written by the current RedisStore instance instead of scanning *; use a non-empty, application-specific prefix when you need reset to cover cache entries across restarts or multiple processes.

Query-Sensitive Caching

Built-in HTTP cache key strategies derive their path segment from the concrete request path (requestContext.request.path), not the route template metadata. That means requests such as /users/1 and /users/2 always resolve to different cache keys even when they hit the same @Get('/:id') handler.

By default, anonymous requests use the concrete request path and ignore query parameters. Authenticated requests append a principal scope when one is available; use principalScopeResolver to customize that suffix. Enable httpKeyStrategy: 'route+query' (or full, which is equivalent for the built-in strategy set) to cache different responses for different search parameters. Query-aware keys canonicalize both parameter names and repeated values, so /products?tag=a&tag=b and /products?tag=b&tag=a share one cache entry.

CacheModule.forRoot({
  store: 'memory',
  httpKeyStrategy: 'route+query',
})

For fully custom keying, pass a function as httpKeyStrategy or use @CacheKey(...) with either a literal key or a key factory.

The HTTP interceptor caches only successful, uncommitted GET handler results with a value that can be replayed later. It skips undefined, SseResponse streams, already committed responses, and responses whose status code is outside the 2xx range, so redirects and error responses are not stored as cache hits.

Cache Ownership and Reset Scope

CacheService.reset() clears entries owned by the configured store, not unrelated application state. It also drops in-flight remember(...) bookkeeping so loaders that started before the reset cannot repopulate stale entries after the reset completes. For the built-in memory store that means the in-process entries held by that store instance. For Redis, ownership is the configured keyPrefix namespace; keep the default fluo:cache: or choose a dedicated prefix such as myapp:cache: for shared Redis deployments.

CacheModule.forRoot({
  store: 'redis',
  keyPrefix: 'myapp:cache:',
})

Avoid sharing a Redis cache prefix with non-cache data. del(key) removes the exact cache key resolved by this package, while reset() removes only the store-owned cache namespace described above.

When the application closes, CacheService forwards shutdown to custom stores that expose close() or dispose(). Use one of those optional hooks when a store owns sockets, pools, timers, or other external resources.

Custom stores can be passed directly through store when they implement the CacheStore contract. This is the right option for in-process LRU stores, remote caches other than Redis, or test doubles that need to observe cache operations.

Manual Module Composition

Use CacheModule.forRoot(...) for normal application setup, including custom defineModule(...) composition.

import { defineModule } from '@fluojs/runtime';
import { CacheInterceptor, CacheModule, CacheService } from '@fluojs/cache-manager';

class ManualCacheModule {}

defineModule(ManualCacheModule, {
  exports: [CacheService, CacheInterceptor],
  imports: [CacheModule.forRoot({ store: 'memory', ttl: 60 })],
});

Memory Store Operational Limits

The built-in memory store is designed for single-process, bounded caching:

  • If you omit ttl on the default memory path, CacheModule.forRoot() uses a 300-second TTL.
  • ttl: 0 is still supported for no-expiry entries, but the memory store keeps only the most recent 1,000 live keys.
  • High-cardinality or multi-instance deployments should use the Redis store instead of relying on process-local memory.

Deferred eviction timing

For non-GET handlers decorated with @CacheEvict(...), eviction is deferred until the response successfully commits. If response.send(...) rejects, the deferred eviction is cancelled so a failed commit does not drop the previous cached read result. If an adapter path never calls response.send(...), the interceptor still runs a bounded fallback timer so successful writes do not leave stale entries behind indefinitely. Deferred eviction failures stay contained inside the interceptor, so cache-key factories or cache-store deletes cannot surface as post-response unhandled promise rejections.

Public API Overview

Modules

  • CacheModule.forRoot(options): Configures the cache store (memory/redis/custom), default TTL, key strategies, global, principalScopeResolver, the Redis namespace keyPrefix, and Redis options such as redis.scanCount. This is the primary package entrypoint for application modules.

Services

  • CacheService: Main API for manual cache operations (get, set, del, remember, reset, close). Application shutdown calls the same close() path, which forwards teardown to custom stores exposing close() or dispose().

Decorators

  • @CacheTTL(seconds): Sets the TTL for a specific handler.
  • @CacheKey(key): Sets a custom cache key or key factory for a specific handler.
  • @CacheEvict(key): Clears one or more cache keys after a successful non-GET handler completes.
  • cacheRouteMetadataKey, getCacheKeyMetadata(...), getCacheTtlMetadata(...), and getCacheEvictMetadata(...): Low-level metadata helpers exported for first-party interceptor integration, diagnostics, and advanced tooling that needs to inspect cache decorator metadata without reimplementing the metadata keys.

Interceptors

  • CacheInterceptor: Handles automatic GET response caching and eviction logic.

Stores and status helpers

  • MemoryStore and RedisStore: Built-in store implementations.
  • CACHE_OPTIONS and CACHE_STORE: DI tokens for package internals and custom composition.
  • createCacheManagerPlatformStatusSnapshot(...) and createCacheManagerPlatformDiagnosticIssues(...): Platform status and diagnostic helpers.

Related Packages

  • @fluojs/redis: Required for Redis storage.
  • @fluojs/http: Required for HTTP interceptors and decorators.

Example Sources

  • packages/cache-manager/src/module.test.ts: Module configuration and provider tests.
  • packages/cache-manager/src/interceptor.test.ts: HTTP caching and eviction tests.
  • packages/cache-manager/src/service.ts: Core CacheService implementation.
  • packages/cache-manager/src/status.test.ts: Status and diagnostic helper tests.