# Cache

URL: https://zerodev.ca/docs/medusa/developer-documentation/cache

> In-memory cache stores for images, renders, messages, and any module data that is expensive to fetch.



`medusa.cache` holds named in-memory stores. Each store keeps entries for a fixed lifetime, evicts the least recently used entry once it is full, and sweeps expired entries every minute. Nothing is written to disk, and every store starts empty after a restart.

<Callout type="warning">
  The cache is never a stand-in for the database. Settings, audit records, and module models always read and write the database directly, and Medusa stops if the database cannot be reached. Only cache data that can be fetched or rebuilt again.
</Callout>

## Stores

```js title="modules/example/src/handlers/profiles.js"
async profile(userId) {
    return this.medusa.cache.store("example.profiles", { ttl: 300000, max: 1000 })
        .remember(userId, () => this.fetch(userId));
}
```

`store(name, options)` returns the same store on every call, so options only apply the first time. Prefix store names with the module id to keep them apart.

| Method                      | Signature                                                            | Description                                                                                                                                                        |
| --------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `get(key)`                  | `(key: any) => any`                                                  | Returns the value, or `undefined` when missing or expired.                                                                                                         |
| `set(key, value, ttl?)`     | `(key: any, value: any, ttl?: number) => any`                        | Stores the value and returns it. `ttl` overrides the store lifetime for this entry.                                                                                |
| `has(key)`                  | `(key: any) => boolean`                                              | Checks for a live entry.                                                                                                                                           |
| `remember(key, load, ttl?)` | `(key: any, load: () => Promise<any>, ttl?: number) => Promise<any>` | Returns the cached value, or runs `load` and caches its result. Concurrent calls for the same key share one `load`. `null` and `undefined` results are not cached. |
| `delete(key)`               | `(key: any) => boolean`                                              | Removes one entry.                                                                                                                                                 |
| `clear()`                   | `() => void`                                                         | Removes every entry.                                                                                                                                               |
| `stats()`                   | `() => object`                                                       | `name`, `size`, `max`, `ttl`, `hits`, and `misses`.                                                                                                                |

## Built-in Stores

| Store            | Lifetime   | Limit | Holds                                                                                    |
| ---------------- | ---------- | ----- | ---------------------------------------------------------------------------------------- |
| `canvas.images`  | 30 minutes | 300   | Images loaded by `medusa.canvas.image(url)`, keyed by URL.                               |
| `canvas.renders` | 5 minutes  | 100   | PNG buffers from `medusa.canvas.render`, keyed by a hash of the layout, data, and scale. |

## Messages

Discord messages are cached by discord.js on each channel (`channel.messages.cache`). Medusa limits every channel to the 200 most recent messages and sweeps messages older than 30 minutes every 5 minutes. `channel.messages.fetch(id)` reads that cache before calling Discord, so repeated lookups of the same panel or review message stay local.
