Expiration and invalidation
Decide how long values stay useful and remove them when the original data changes.
Choose how long a cached value can be reused, and remove it when a relevant application change makes it stale.
Set a lifetime
A time to live (TTL) is how long a cached value can be reused. The prices cache uses one minute by default:
/** Declares integer SKU prices in the requests cache profile with a one-minute default and five-minute maximum TTL. */
import { defineCache } from "@relkit/app/cache";
import { z } from "@relkit/app/schema";
const prices = defineCache({
id: "orders.prices",
profile: "requests",
key: z.object({ sku: z.string() }),
value: z.number().int().nonnegative(),
defaultTtlMs: 60_000,
maxTtlMs: 300_000,
});
export default prices;
To use a shorter lifetime for one write, call await context.cache.prices.set({ sku: "book" }, 1200, { ttlMs: 10_000 }). getOrSet() accepts the same options as its third argument when saving a newly loaded value.
TTL values must be positive integers in milliseconds. Here, a value above 300_000 is rejected. Reading a cached value does not restart its lifetime, and getOrSet() does not change an existing entry’s TTL on a hit.
Remove stale values after a change
When a product price changes, save the new price to your database first. Then call await context.cache.prices.delete({ sku: "book" }). The next getOrSet() call loads the new price.
This is invalidation: removing a cached copy because you know it may be outdated. It complements TTL; you do not have to wait for expiration after a known change. An event function can invalidate the cache after a product-update event too.
If results depend on a user, tenant, currency, or permissions, include those details in your key. Otherwise, one request can reuse another request’s data.
Test freshness
Test a missing entry, a hit, expiration, and deletion. Use a controllable clock in tests instead of waiting for a real minute.
After adding those tests, run from your app’s root:
bun run test
Keep your database as the source of truth. A cache error is not a cache miss: decide whether your app should fail the request or read the original data when caching is unavailable.