Skip to content

Cache

The fastedge::cache module is a fast key/value store scoped to a single point of presence (POP). Reads and writes are sub-millisecond, and the API exposes atomic counter primitives that make it suitable for rate limits, quotas, locks, and request coalescing within a POP.

Writes do not replicate to other POPs. A value written from one data center is invisible to another. This is the trade-off that makes the cache fast and strongly consistent locally — and is the right choice for transient, request-time state. For globally-replicated, eventually-consistent storage use fastedge::kv.

Propertyfastedge::cachefastedge::kv
ScopeOne POPAll POPs
ConsistencyStrong within a POPEventual; globally replicated
Atomic countersincr, decr, getOrSet coalescingNot available
PersistenceEvicted; no durability guaranteeDurable across deployments
Typical useRate limits, counters, response memoisingConfiguration, lookup tables, sorted sets

Cache is a static class — never instantiated. Every method returns a Promise.

import { Cache } from 'fastedge::cache';
async function eventHandler(event) {
const ip = event.client.address ?? 'unknown';
const count = await Cache.incr(`rl:${ip}`);
if (count === 1) await Cache.expire(`rl:${ip}`, { ttl: 60 });
if (count > 100) {
return new Response('Too Many Requests', { status: 429 });
}
return new Response('ok');
}
addEventListener('fetch', (event) => {
event.respondWith(eventHandler(event));
});

Cache.set, Cache.expire, and Cache.getOrSet accept a WriteOptions object controlling expiry. Pass exactly one of ttl, ttlMs, or expiresAt. Passing more than one — or zero/negative values — throws TypeError. Omit options entirely (or pass {}) for no expiry.

FieldUnitDescription
ttlseconds from nowThe conventional unit for cache and KV APIs
ttlMsmilliseconds from nowUse for sub-second granularity (short windows)
expiresAtUnix epoch secondsAbsolute deadline (e.g. “expire at midnight”)

Cache.set and the populate callback of Cache.getOrSet accept any CacheValue. All forms are coerced to raw bytes before storage.

type CacheValue = string | ArrayBuffer | ArrayBufferView | ReadableStream | Response;
  • string — encoded as UTF-8.
  • ArrayBuffer / ArrayBufferView — used directly.
  • ReadableStream — fully consumed into a single byte buffer.
  • Response — the body is consumed via await response.arrayBuffer(). Status and headers are discarded; if you need to round-trip them, encode as a JSON envelope yourself.

Operational errors from the host (access denied, internal error) surface as Promise rejections. Validation errors on call arguments (wrong types, conflicting WriteOptions fields) are thrown synchronously. Both are caught the same way by try/catch around an await.