Skip to docs content
Browse documentation
On this page

One source of truth

Keep each fact in one record. Anything derived from it is a cache, and the write path refreshes that cache.

Keep each fact in one normalized record. A table, map or index built from that record is a cache. The code that writes the fact also refreshes the cache, before anyone can read the stale copy.

A time-to-live is the wrong refresh when missing the new fact is worse than recomputing it.

Example

A package declares its event subscriptions in its manifest. That manifest is the truth. The subscriptions table is derived from it:

/**
 * Package event subscriptions, synced from the runnable version's manifest whenever it
 * changes (publish, lock, unlock), like jobs. Handlers run as the member who made that
 * version runnable.
 */

Every sync deletes topics the manifest no longer declares and upserts the rest in one transaction. Jobs work the same way. You never edit a subscription or a job schedule directly; you publish a new version and the derived rows follow. See Package subscriptions .

The sandbox bundle cache goes further. It refuses to store anything whose truth could move underneath it:

// Only package-free bundles are cached: package imports resolve to whatever version is
// runnable now, and carry per-bundle access tokens.
if (built.packageIds.length === 0) {
    cache.set(cacheKey, built.code)

In your packages

Pick one home for each piece of state (see Persist named state ). If a package keeps a summary in packageStorage() that's built from somewhere else, update or delete the summary in the same code that changes the original. Don't keep the same id in two packages; export it from the one that owns it.