Skip to content
RELKIT
Esc
↑↓navigate↵open⌘Jpreview
On this page

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.