> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/whiskeysockets/Baileys/llms.txt
> Use this file to discover all available pages before exploring further.

# makeCacheableSignalKeyStore

> Add in-memory caching to SignalKeyStore implementations for improved performance

The `makeCacheableSignalKeyStore` function wraps a `SignalKeyStore` with an in-memory cache to reduce database queries and improve performance.

## Function Signature

```typescript theme={null}
function makeCacheableSignalKeyStore(
  store: SignalKeyStore,
  logger?: ILogger,
  _cache?: CacheStore
): SignalKeyStore
```

## Parameters

<ParamField path="store" type="SignalKeyStore" required>
  The underlying key store to add caching to. Can be any implementation of `SignalKeyStore`.
</ParamField>

<ParamField path="logger" type="ILogger">
  Optional logger to trace cache operations. Logs events like:

  * Cache hits/misses
  * Number of items loaded from store
  * Cache update operations
</ParamField>

<ParamField path="_cache" type="CacheStore">
  Optional custom cache implementation. If not provided, uses a default `NodeCache` with:

  * **TTL**: 5 minutes (300 seconds)
  * **useClones**: false (stores references, not copies)
  * **deleteOnExpire**: true (automatically removes expired entries)
</ParamField>

## Returns

<ResponseField name="SignalKeyStore" type="SignalKeyStore" required>
  A cached wrapper around the original store with the same interface

  <Expandable title="methods">
    <ResponseField name="get" type="async function">
      Retrieves keys, checking cache first before querying the store

      ```typescript theme={null}
      async get<T extends keyof SignalDataTypeMap>(
        type: T, 
        ids: string[]
      ): Promise<{ [id: string]: SignalDataTypeMap[T] }>
      ```
    </ResponseField>

    <ResponseField name="set" type="async function">
      Writes to both cache and underlying store

      ```typescript theme={null}
      async set(data: SignalDataSet): Promise<void>
      ```
    </ResponseField>

    <ResponseField name="clear" type="async function">
      Clears both cache and underlying store

      ```typescript theme={null}
      async clear?(): Promise<void>
      ```
    </ResponseField>
  </Expandable>
</ResponseField>

## Usage Example

```typescript theme={null}
import { 
  makeCacheableSignalKeyStore,
  useMultiFileAuthState 
} from '@whiskeysockets/baileys'

// Create base auth state
const { state } = await useMultiFileAuthState('./auth_info')

// Wrap the key store with caching
const cachedState = {
  ...state,
  keys: makeCacheableSignalKeyStore(
    state.keys,
    logger, // your logger instance
    customCache // optional custom cache
  )
}

// Use cached state with socket
const sock = makeWASocket({ auth: cachedState })
```

## How It Works

### Cache Keys

Cache keys are generated using a combination of type and ID:

```typescript theme={null}
function getUniqueId(type: string, id: string) {
  return `${type}.${id}`
}

// Examples:
// "pre-key.1"
// "session.123456789@s.whatsapp.net"
// "app-state-sync-key.abc123"
```

### Get Operation Flow

1. **Check cache** for each requested ID
2. **Collect cache misses** in `idsToFetch` array
3. **Query store** only for missing IDs
4. **Update cache** with fetched items
5. **Return combined** results (cached + fetched)

```typescript theme={null}
async get(type, ids) {
  return cacheMutex.runExclusive(async () => {
    const data = {}
    const idsToFetch = []

    // Check cache first
    for (const id of ids) {
      const item = await cache.get(getUniqueId(type, id))
      if (typeof item !== 'undefined') {
        data[id] = item
      } else {
        idsToFetch.push(id)
      }
    }

    // Fetch missing from store
    if (idsToFetch.length) {
      logger?.trace({ items: idsToFetch.length }, 'loading from store')
      const fetched = await store.get(type, idsToFetch)
      
      // Cache fetched items
      for (const id of idsToFetch) {
        const item = fetched[id]
        if (item) {
          data[id] = item
          await cache.set(getUniqueId(type, id), item)
        }
      }
    }

    return data
  })
}
```

### Set Operation Flow

1. **Update cache** with all provided data
2. **Write to store** (pass-through to underlying implementation)
3. **Log operation** if logger provided

```typescript theme={null}
async set(data) {
  return cacheMutex.runExclusive(async () => {
    let keys = 0
    
    // Update cache
    for (const type in data) {
      for (const id in data[type]) {
        await cache.set(getUniqueId(type, id), data[type][id])
        keys += 1
      }
    }

    logger?.trace({ keys }, 'updated cache')
    
    // Write to store
    await store.set(data)
  })
}
```

### Thread Safety

All cache operations are protected by a mutex to prevent race conditions:

```typescript theme={null}
const cacheMutex = new Mutex()

// All operations run exclusively
await cacheMutex.runExclusive(async () => {
  // Cache operations here
})
```

## Performance Benefits

<AccordionGroup>
  <Accordion title="Reduced Database Queries">
    Frequently accessed keys (like sessions) are served from memory, significantly reducing database load.
  </Accordion>

  <Accordion title="Lower Latency">
    In-memory cache access is orders of magnitude faster than disk/database access.
  </Accordion>

  <Accordion title="Automatic Expiration">
    Default 5-minute TTL ensures cache doesn't grow unbounded while keeping hot data available.
  </Accordion>
</AccordionGroup>

## Custom Cache Implementation

You can provide a custom cache that implements the `CacheStore` interface:

```typescript theme={null}
interface CacheStore {
  get<T>(key: string): Promise<T> | T | undefined
  set<T>(key: string, value: T): Promise<void> | void | number | boolean
  del(key: string): void | Promise<void> | number | boolean
  flushAll(): void | Promise<void>
}
```

### Example: Redis Cache

```typescript theme={null}
import { createClient } from 'redis'

const redisClient = await createClient().connect()

const redisCache: CacheStore = {
  async get(key) {
    const value = await redisClient.get(key)
    return value ? JSON.parse(value) : undefined
  },
  async set(key, value) {
    await redisClient.setEx(key, 300, JSON.stringify(value))
  },
  async del(key) {
    await redisClient.del(key)
  },
  async flushAll() {
    await redisClient.flushAll()
  }
}

const cachedStore = makeCacheableSignalKeyStore(
  baseStore,
  logger,
  redisCache
)
```

## Related

* [SignalKeyStore](/api/auth/auth-state#signalkeystore) - Base key store interface
* [useMultiFileAuthState](/api/auth/multi-file-auth-state) - File-based auth state
* [AuthenticationState](/api/auth/auth-state) - Complete authentication state documentation
