Configure the object cache

On this page

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.

Overview

BackendBest forShared across isolates
KVCloudflare WorkersYes
MemoryNode.js, local developmentNo (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.

Cloudflare KV

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

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" }),
		}),
	],
});

Setup

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

npx wrangler kv namespace create CACHE

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

wrangler.jsonc

{
  "kv_namespaces": [
    {
      "binding": "CACHE",
      "id": "<namespace-id>"
    }
  ]
}

wrangler.toml

[[kv_namespaces]]
binding = "CACHE"
id = "<namespace-id>"

Options

OptionTypeDefaultDescription
bindingstring—KV binding name from your Wrangler configuration. Required.
defaultTtlnumber3600Time-to-live for cached entries, in seconds. KV enforces a 60-second minimum.
revalidatenumber1000Isolate-local epoch-reuse window, in milliseconds. See Freshness.
timeoutnumber2000Maximum 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.
keyPrefixstring"em"Prefix for every cache key. Set a unique value when several sites share one namespace.

Node.js (memory)

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

import emdash, { memoryCache } from "emdash/astro";
import { sqlite } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: sqlite({ url: "file:./data.db" }),
			objectCache: memoryCache(),
		}),
	],
});

Options

OptionTypeDefaultDescription
defaultTtlnumber3600Time-to-live for cached entries, in seconds.
revalidatenumber1000Isolate-local epoch-reuse window, in ms.
maxEntriesnumber1000Maximum number of cached keys before older keys evict.
keyPrefixstring"em"Prefix for every cache key.

What gets cached

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 hit in the HTML layer does not run EmDash. A miss runs the Worker, and a response that may fill Astro’s route cache bypasses the object cache. Its content queries read from the database, which prevents a page purged after a content change from being rebuilt with an older KV snapshot.

Freshness

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 requests that are not route-cache fills, 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 content

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.