Crux
API Reference@use-crux/core

RecordStore

JSON record storage methods, capabilities, TTL, filters, and bundled adapters.

RecordStore is the JSON record capability from @use-crux/core/storage.

import { inMemoryRecordStore, keySpace } from "@use-crux/core/storage";
import type { JsonObject, RecordStore } from "@use-crux/core/storage";

const records = inMemoryRecordStore();
await records.put("plan:abc", { title: "My Plan", version: 1 });
const plan = await records.get("plan:abc");

Use RecordStore for memory records, cache entries, flow snapshots, plans, tasks, blackboards, workspace metadata, and other structured Crux state. Use VectorStore for similarity search and AssetStore for binary or oversized payloads.

Interface

interface RecordStore<T extends JsonObject = JsonObject> {
  get(key: string): Promise<T | null>;
  getMany?(keys: readonly string[]): Promise<readonly (T | null)[]>;
  put(key: string, value: T, options?: { ttlMs?: number }): Promise<void>;
  putMany?(
    entries: readonly { key: string; value: T; options?: { ttlMs?: number } }[],
  ): Promise<void>;
  create(key: string, value: T, options?: { ttlMs?: number }): Promise<boolean>;
  delete(key: string): Promise<void>;
  deleteMany?(keys: readonly string[]): Promise<void>;
  list(prefix: string, options?: RecordListOptions): Promise<RecordPage<T>>;
  scan?(
    prefix: string,
    options?: Omit<RecordListOptions, "cursor">,
  ): AsyncIterable<RecordEntry<T>>;
  watch?(prefix: string, callback: (event: RecordEvent<T>) => void): () => void;
  capabilities(): RecordStoreCapabilities;
}

put() creates or replaces a record. create() is the atomic insert primitive and returns false when an active record already exists.

Capabilities

type RecordStoreCapabilities = {
  ttl: "native" | "lazy" | false;
  filter: "native" | "scan" | false;
  watch: boolean;
  batch: boolean;
};

Adapters must report the behavior they actually provide. Passing { ttlMs } to a store with ttl: false throws StorageError code ttl_unsupported.

Filters

Filters are exact top-level scalar equality:

await records.list("docs:", {
  filter: { namespace: "public", active: true, deletedAt: null },
});

Unsupported filter values must throw StorageError code invalid_filter; adapters should not silently drop unsupported clauses.

Watches

watch(prefix, callback) emits put and delete events when a backend supports live notifications:

records.watch?.("plan:", (event) => {
  if (event.type === "put") {
    console.log("Updated:", event.key, event.value);
  } else {
    console.log("Deleted:", event.key);
  }
});

Keyspace

keySpace centralizes Crux record-key prefixes used by core primitives:

const key = keySpace.plan.key("abc");
const page = await records.list(keySpace.plan.prefix);

Implementations

StorePackageUse case
inMemoryRecordStore()@use-crux/core/storageTests and local examples
convexRecordStore()@use-crux/convexConvex-backed records
upstashRedisRecordStore()@use-crux/upstashUpstash Redis-backed records

Bundle records with vectors and assets through storage({ records, vectors, assets }) when a primitive needs multiple capabilities.

On this page