Cache Schema Guide

June 27, 2026 · View on GitHub

How to add fixed and template keys. Aligned with Preference Schema Guide and Boot Config Schema Guide.

Schemas

SchemaTierFileDefault map
UseCacheSchemaMemorysrc/shared/data/cache/cacheSchemas.tsDefaultUseCache
SharedCacheSchemaSharedsrc/shared/data/cache/cacheSchemas.tsDefaultSharedCache
RendererPersistCacheSchemaPersist (Renderer)src/shared/data/cache/cacheSchemas.tsDefaultRendererPersistCache
MainPersistCacheSchemaPersist (Main)src/shared/data/cache/cacheSchemas.tsDefaultMainPersistCache

Complex value types go in src/shared/data/cache/cacheValueTypes.ts and are imported via CacheValueTypes.*.

Naming Convention

Enforced by ESLint rule data-schema-key/valid-key. Pattern: /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.

ValidInvalidWhy
app.user.avataruserAvatarNo dot separator
chat.multi_select_modechat.multiSelectModeNo camelCase
scroll.position.${topicId}scroll.position:${id}Colon not allowed
entity.cache.${type}_${id}App.userNo uppercase

Template placeholders ${xxx} are treated as literal segments for the naming check. At runtime, the placeholder name is ignored — ${providerId} and ${foo} produce identical regex; each placeholder expands to [\w\-]+ (no dots, no colons, no non-ASCII).

Choosing Fixed / Template / Casual

Fixed keyTemplate keyCasual (Memory only)
Type inferenceAutomaticAutomaticManual generic
Compile-time validationYesYesNo
Dynamic segmentsNoYesYes
Shared tierYesYesNot supported
Persist tierYesNot supportedNot supported
Default valuePer keyShared across instancesNone

Prefer Fixed > Template > Casual. Cross-window dynamic keys must be Template — there is no getSharedCasual.

Adding a Fixed Key

1. Add the entry

// src/shared/data/cache/cacheSchemas.ts
export type UseCacheSchema = {
  // ...existing entries
  'feature.my_feature.data': MyDataType
}

export const DefaultUseCache: UseCacheSchema = {
  // ...existing defaults
  'feature.my_feature.data': { items: [], lastUpdated: 0 }
}

2. Define complex value type (if needed)

// src/shared/data/cache/cacheValueTypes.ts
export interface MyDataType {
  items: string[]
  lastUpdated: number
}

3. Use it

const [data, setData] = useCache('feature.my_feature.data')
// data is MyDataType

Adding a Template Key

// cacheSchemas.ts
export type UseCacheSchema = {
  'scroll.position.${topicId}': number
}

export const DefaultUseCache: UseCacheSchema = {
  'scroll.position.${topicId}': 0  // shared by every concrete instance
}

Use with any string in the dynamic segment:

const [pos, setPos] = useCache(`scroll.position.${topicId}`)
// pos is number; default 0 for every topicId that hasn't been written yet

The placeholder name is documentation-only. ${topicId} and ${id} compile to the same runtime matcher. Pick a name that matches the concept (not convention).

Shared and Persist Variants

  • Shared: add to SharedCacheSchema / DefaultSharedCache. Fixed and template both supported.
  • Persist: add to RendererPersistCacheSchema / DefaultRendererPersistCache. Fixed keys only. Persist values survive restart via localStorage — keep them small and typed.

Validation

CheckCommand / location
ESLint naming rulepnpm lint (rule: data-schema-key/valid-key)
Template matching unit testssrc/shared/data/cache/__tests__/templateKey.test.ts
Schema exhaustivenessTypeScript compiler — default map must satisfy the schema type

See Also