Skip to content

Configure the object cache

EmDash’s per-request cache already deduplicates identical reads during one page render. The optional object cache keeps selected query results across requests, allowing a later request to avoid the same database read. It is useful when public traffic creates more database reads than the selected backend should handle.

The database remains the source of truth. Cache reads fail open to the database, and writes invalidate the affected cache namespace. The object cache is disabled by default; enable it by adding an objectCache adapter to the emdash() integration.

Backend Best for Shared across isolates
KV Cloudflare Workers Yes
Memory Node.js, local development No (per process)

On Cloudflare, requests are served by many short-lived isolates across regions. KV is shared by all of them, so a value cached by one request is available to the next, anywhere. The memory backend caches within a single process, which suits a long-running Node.js server.

Configure the KV adapter and point it at a KV binding:

astro.config.mjs
import emdash from "emdash/astro";
import { d1, r2, kvCache } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: d1({ binding: "DB" }),
storage: r2({ binding: "MEDIA" }),
objectCache: kvCache({ binding: "CACHE" }),
}),
],
});

Create a KV namespace and add the binding to your Wrangler configuration.

Terminal window
npx wrangler kv namespace create CACHE

The command prints a namespace id. Add it under the binding name used in kvCache:

{
"kv_namespaces": [
{
"binding": "CACHE",
"id": "<namespace-id>"
}
]
}
Option Type Default Description
binding string — KV binding name from your Wrangler configuration. Required.
defaultTtl number 3600 Time-to-live for cached entries, in seconds. KV enforces a 60-second minimum.
revalidate number 1000 Isolate-local epoch-reuse window, in milliseconds. See Freshness.
timeout number 2000 Maximum time, in milliseconds, to wait for a KV operation before treating it as a cache miss. Guards against a stalled KV read hanging the request. Set to 0 to disable.
keyPrefix string "em" Prefix for every cache key. Set a unique value when several sites share one namespace.

The memory adapter caches within the server process. It needs no external service:

astro.config.mjs
import emdash, { memoryCache } from "emdash/astro";
import { sqlite } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: sqlite({ url: "file:./data.db" }),
objectCache: memoryCache(),
}),
],
});
Option Type Default Description
defaultTtl number 3600 Time-to-live for cached entries, in seconds.
revalidate number 1000 Isolate-local epoch-reuse window, in ms.
maxEntries number 1000 Maximum number of cached keys before older keys evict.
keyPrefix string "em" Prefix for every cache key.

The object cache covers the reads that run on a typical page render:

  • Content queries: getEmDashCollection, getEmDashEntry, and resolveEmDashPath.
  • Site settings, navigation menus, and taxonomy terms.

Admin API requests, media files, and full HTML responses are not handled here. To cache rendered HTML at the edge, see Deploy to Cloudflare.

The object cache and an HTML edge cache solve different problems. A cache miss in the HTML layer still runs the Worker; the object cache can then prevent repeated content queries. A hit in the HTML layer does not run EmDash at all.

Editing content through the admin panel or the REST API invalidates the affected cache entries automatically. Creating, updating, publishing, or deleting an entry clears the cached queries for its collection; changing a byline or taxonomy term clears the entries that display it.

For anonymous visitors, a change takes time to appear across all isolates as they pick up the bumped epoch. With the in-isolate memory backend this is immediate. With Workers KV it is bounded by KV’s edge-cache propagation (eventual consistency, up to ~60 seconds) plus the isolate-local revalidate window (default one second). Lower revalidate for faster local propagation at the cost of more reads against the cache; raise it to read the cache less often.

Scheduled entries become visible when their publish time passes. A cached page reflects a newly-published scheduled entry on the next change to its collection, or when the cached entry’s defaultTtl lapses. If precise scheduled publishing matters for your site, set a lower defaultTtl.