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

# Cache

Cache is a fast key-value store co-located with each FastEdge POP (Point of Presence). It is intended for transient, request-time state — counters, memoized computations, idempotency tokens — and is available to every FastEdge application on a paid plan at runtime without needing to be created or linked in advance.

<Info>
  Cache does not need to be created or linked to your application. It is available at runtime by importing the cache module from the SDK.
</Info>

## Behavior and limits

Cache data lives inside a single POP. Writes are not replicated to other POPs, and a value written in one location is not visible from another. Within a POP, reads and writes are strongly consistent.

Entries are evictable and carry no durability guarantee. A value may disappear before its expiration if the POP is under memory pressure. Cache is not a substitute for persistent storage.

Integer values can be incremented and decremented atomically within a POP, making Cache a natural fit for rate limiting and fixed-window throttling. The `incr` function accepts a signed delta — a positive value increments, a negative value decrements.

The JavaScript SDK provides a `getOrSet` operation: if the key exists, its value is returned immediately; if not, a provided callback computes the value, stores it, and returns it. This is useful for read-through caching where computation is expensive.

`purge` removes all cache keys visible to the application; `purgePrefix` removes all keys whose names begin with a given string. Both return the number of keys deleted. Because Cache is shared across all applications for an account at a POP, these operations affect every key visible to your account at that POP, not only those written by the calling application.

## Cache vs Edge Storage

Cache and [Edge Storage](/fastedge/kv-stores/how-it-works) solve different problems. Use this table to decide which one fits your workload.

|                     | Cache                                                                          | Edge Storage                                                                        |
| ------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
| Scope               | Single POP                                                                     | Globally replicated to all POPs                                                     |
| Consistency         | Strong (within a POP)                                                          | Eventual (1–2 seconds globally)                                                     |
| Durability          | Transient, evictable                                                           | Durable, backed by a central database                                               |
| Provisioning        | None — available at runtime on paid plans                                      | Created in the Customer Portal and linked to your application                       |
| Writes from the API | No (runtime only)                                                              | Yes                                                                                 |
| Atomic counters     | Yes (`incr`; `decr` JS only)                                                   | No                                                                                  |
| Typical workloads   | Rate limits, response memoization, idempotency keys, per-request deduplication | Configuration, feature flags, lookup tables, blocklists, sorted sets, Bloom Filters |

A common pattern is to use both together: store the source of truth in Edge Storage and use Cache to memoize derived results or enforce per-POP rate limits.

## Available operations

| Operation     | Description                                                                            |
| ------------- | -------------------------------------------------------------------------------------- |
| `get`         | Fetch a cached value by key. Returns `None`/`null` on a miss.                          |
| `set`         | Write or overwrite a value with an optional TTL.                                       |
| `delete`      | Remove a key from the cache.                                                           |
| `exists`      | Check whether a key is present without fetching its value.                             |
| `incr`        | Atomically increment (or decrement) an integer counter.                                |
| `decr`        | Decrement a counter. JavaScript SDK only.                                              |
| `expire`      | Set or update the TTL of an existing key. Returns `false` if the key no longer exists. |
| `getOrSet`    | Fetch a value, or compute and store it if missing. JavaScript SDK only.                |
| `purge`       | Delete all cache keys visible to the application at the current POP.                   |
| `purgePrefix` | Delete all keys whose names begin with a given prefix.                                 |

In the JavaScript SDK, expiration is specified per write as `{ ttl: seconds }`, `{ ttlMs: milliseconds }`, or `{ expiresAt: unixTimestamp }`. In the Rust SDK, TTL is always in milliseconds (`Option<u64>`). Entries with no expiration remain until evicted.

## SDK examples

The following examples cover the most common Cache patterns. For the full API reference, see the [JavaScript SDK](https://g-core.github.io/FastEdge-sdk-js/reference/fastedge/cache/) and [Rust SDK](https://docs.rs/fastedge/latest/fastedge/cache/) documentation.

### Read and write a value

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    import { Cache } from 'fastedge::cache';

    await Cache.set('config:feature-x', 'enabled', { ttl: 300 }); // 5-minute TTL

    const value = await Cache.get('config:feature-x');
    if (value === null) {
      // cache miss — compute and store
    }

    await Cache.delete('config:feature-x');
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    use fastedge::cache;

    cache::set("config:feature-x", b"enabled".to_vec(), Some(300_000))?; // 5 min in ms

    match cache::get("config:feature-x")? {
        Some(data) => {
            let value = String::from_utf8_lossy(&data);
            // use value
        }
        None => {
            // cache miss — compute and store
        }
    }

    cache::delete("config:feature-x")?;
    ```
  </Tab>
</Tabs>

### Rate limiting with an atomic counter

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    import { Cache } from 'fastedge::cache';

    const ip = event.client.address ?? 'unknown';
    const key = `rl:${ip}`;

    const count = await Cache.incr(key);
    if (count === 1) {
      // First request in the window — set a 60-second TTL
      await Cache.expire(key, { ttl: 60 });
    }

    if (count > 100) {
      return new Response('Too Many Requests', { status: 429 });
    }
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    use fastedge::cache;

    let ip = request.headers()
        .get("x-real-ip")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("unknown");

    let key = format!("rl:{ip}");

    // Increment by 1; create the counter at 0 if it does not exist
    let count = cache::incr(&key, 1)?;

    if count == 1 {
        // First request in the window — set a 60-second TTL (60 000 ms)
        cache::expire(&key, 60_000)?;
    }

    if count > 100 {
        return Ok(Response::builder()
            .status(429)
            .body(Body::from("Too Many Requests"))?);
    }
    ```
  </Tab>
</Tabs>
