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.
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.
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 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 and Rust SDK documentation.
Read and write a value
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');
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")?;
Rate limiting with an atomic counter
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 });
}
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"))?);
}