Skip to content

KV Store

Ironflow provides a general-purpose key-value store backed by NATS JetStream. User buckets are namespaced under an internal APP_ prefix so they cannot collide with system-level state (SYS_config_*, SYS_secrets_*). Operations include CRUD with revision tracking, atomic create/update (CAS), tombstone-style delete, history purge, key listing, and real-time watch over WebSocket.

  • Buckets: Namespaced containers with optional description, TTL, max value size, max bucket size, and per-key history depth.
  • Atomic operations: create uses If-None-Match: * (if-not-exists) and update uses If-Match: <revision> (compare-and-swap). Both return HTTP 412 on conflict.
  • Soft delete + purge: delete writes a tombstone (preserves history); purge removes the key and its history.
  • Key listing: listKeys with optional wildcard filter (e.g., user.*).
  • Real-time watch: Browser SDK opens a WebSocket to /api/v1/kv/buckets/{name}/watch and emits kv_update events. Optional key filter scopes the stream.
  • Event-driven: Every write is a JetStream message, so audit logs and triggers can be layered on top.
interface KVBucketConfig {
name: string;
description?: string;
ttlSeconds?: number; // 0 = no expiry
maxValueSize?: number; // bytes per value
maxBytes?: number; // bucket-wide cap
history?: number; // revisions kept per key (default 1)
}
import { createClient } from "@ironflow/node";
const client = createClient({ apiKey: process.env.IRONFLOW_API_KEY });
const kv = client.kv();
// Create a bucket with 1h TTL and 5 revisions of history
await kv.createBucket({
name: "settings",
ttlSeconds: 3600,
history: 5,
});
const bucket = kv.bucket("settings");
// Unconditional put
await bucket.put("theme", { mode: "dark" });
// Atomic create — fails if key exists (HTTP 412)
await bucket.create("flags", { betaEnabled: false });
// Read with revision
const entry = await bucket.get("theme");
console.log(entry.value, entry.revision);
// Compare-and-swap update
await bucket.update("theme", { mode: "light" }, entry.revision);
// List keys with wildcard filter
const keys = await bucket.listKeys("user.*");
// Soft delete (tombstone) and full purge
await bucket.delete("flags");
await bucket.purge("flags");
// Bucket management
const buckets = await kv.listBuckets();
const info = await kv.getBucketInfo("settings");
await kv.deleteBucket("settings");
import { ironflow } from "@ironflow/browser";
ironflow.configure({ serverUrl: "http://localhost:9123" });
const bucket = ironflow.kv().bucket("settings");
const entry = await bucket.get("theme");
// Real-time watch over WebSocket
const watcher = bucket.watch(
{
onUpdate: (event) => console.log(event.key, event.value),
onError: (err) => console.error(err),
onClose: () => console.log("watch closed"),
},
{ key: "theme" } // optional filter
);
// Later
watcher.stop();
FeatureUse ForBucket PrefixEncrypted
KV StoreSessions, caching, counters, app dataAPP_*No
ConfigApp settings, feature flags, togglesSYS_config_*No
SecretsAPI keys, DB passwords, certificatesSYS_secrets_*Yes (AES-256-GCM)

The KV Store dashboard only lists APP_-prefixed buckets; SYS_* buckets are hidden from the user-facing UI.