# ZoneCache

The ZoneCache stores data in a shared cache that is local to a single zone (data
center or cluster). Each zone maintains its own independent cache — data written
in one zone is not synchronized or replicated to other zones. If the same data
is needed in multiple zones, it must be written to each zone's cache
independently.

This makes ZoneCache ideal for caching configuration, reference data, or
expensive API responses to reduce latency. It is not suitable for transactional,
OLTP-style workloads where consistency across locations matters.

The ZoneCache can store any JSON serializable data. Each cached item has a
time-to-live (TTL) after which it expires and is removed from the cache. Each
cached object can be up to 512 MB in size.

There's an demonstration of ZoneCache use in the
[Per User Rate Limits Using a Database](../articles/per-user-rate-limits-using-db.mdx)
example.

## Constructor

```ts
new ZoneCache<T = unknown>(name: string, context: ZuploContext)
```

Creates a new cache instance for the specified zone.

- `name` - A unique identifier for the cache
- `context` - The [ZuploContext](./zuplo-context.mdx) object
- `T` - The type of data stored in the cache (defaults to `unknown`)

## Methods

**`get`**

Retrieves a value from the cache. Returns `undefined` if the key doesn't exist
or has expired.

```ts
get(key: string): Promise<T | undefined>
```

**`put`**

Stores a value in the cache with a time-to-live (TTL) in seconds. The data will
be JSON serialized.

```ts
put(key: string, data: T, ttlSeconds: number): Promise<void>
```

:::note

Objects that don't serialize cleanly to JSON (like the `Headers` object) won't
be readable after storage.

:::

**`delete`**

Removes a value from the cache.

```ts
delete(key: string): Promise<void>
```

## Example

```ts
import { ZoneCache, ZuploContext, ZuploRequest } from "@zuplo/runtime";

interface UserData {
  id: string;
  name: string;
  email: string;
}

export default async function handler(
  request: ZuploRequest,
  context: ZuploContext,
) {
  const cache = new ZoneCache<UserData>("user-cache", context);

  // Try to get user from cache
  const userId = request.params.userId;
  let userData = await cache.get(userId);

  if (!userData) {
    // Not in cache, fetch from API
    const response = await fetch(`https://api.example.com/users/${userId}`);
    userData = await response.json();

    // Cache for 5 minutes
    await cache.put(userId, userData, 300);
  }

  return new Response(JSON.stringify(userData));
}
```

## Performance tips

When writing to the cache, you may not want to `await` the operation to
complete. This can improve response times:

```ts
// Fire and forget pattern - don't wait for cache write
cache.put("key", data, 60).catch((err) => context.log.error(err));
```

Always catch errors when using the fire-and-forget pattern to avoid unhandled
promise rejections.

## When to use ZoneCache

ZoneCache works well for:

- **Configuration and reference data** — API keys, feature flags, routing rules,
  or other config that changes infrequently
- **Expensive API responses** — results from slow or rate-limited upstream
  services
- **Computed data** — pre-processed results that are costly to regenerate

:::caution{title="Not a distributed data store"}

ZoneCache is a per-zone cache with **no cross-zone synchronization**. A `put()`
in one data center has no effect on the cache in any other data center. Do not
use it as a database, key/value store, or for any OLTP-style read/write
workload. It is not appropriate for data where global consistency matters.

:::

## Limits

For full Zuplo platform limits see the
[Zuplo Limits documentation](../articles/limits.mdx).

- Maximum size per cached item: 512 MB
- Maximum cache calls per request: 1000
