- Storage, Config & Secrets
- Config Patterns
Config Patterns
Patterns & Best Practices
Config vs KV Store
While both use NATS JetStream under the hood, they solve different problems.
| Feature | Config Management | KV Store |
|---|---|---|
| Model | JSON Documents (Objects). | Individual Keys (Raw). |
| Scoping | Automatic per Environment. | Manual per Bucket. |
| Updates | Full set or shallow patch. | put, create, or update. |
| Best For | Feature flags, App settings. | Caching, sessions, counters. |
Pattern: Feature Flags
Store all your flags in a single JSON document. This allows your frontend or workers to load all active flags in a single network request.
import { createClient } from "@ironflow/node";
const ironflow = createClient({ apiKey: process.env.IRONFLOW_API_KEY });const config = ironflow.config();
// 1. Define the flagsawait config.set("flags", { "new-onboarding": true, "promo-banner": false, "max-items": 10});
// 2. Patch one flag without affecting othersawait config.patch("flags", { "promo-banner": true });// Patch a single flag_, err := client.Config().Patch(ctx, "flags", map[string]any{ "promo-banner": true,})import osfrom ironflow import IronflowClient
client = IronflowClient(api_key=os.environ["IRONFLOW_API_KEY"])
# 1. Define the flags (POST — full replacement)client.config_create("flags", body={ "new-onboarding": True, "promo-banner": False, "max-items": 10,})
# 2. Patch one flag without affecting othersclient.config_patch("flags", body={"promo-banner": True})
# Read them back — the document sits under "data"doc = client.config_get("flags")print(doc["data"]["max-items"], doc["revision"])
# Discovery & cleanupfor entry in client.config_list()["configs"]: print(entry["name"])client.config_delete("legacy-flags")config_create is the POST route, which is a full replacement despite the
create name — it is the equivalent of set(), not a create-if-absent. There
is no Python equivalent of the watch pattern below: config watch is a
long-lived stream and is deliberately not generated.
Pattern: Application Settings
Centralize your server-side constants (timeouts, URLs, thresholds). Your workers can fetch these at startup or watch for changes to update their behavior without a restart.
const settings = await config.get("worker-settings");
if (settings.data.maintenanceMode) { process.exit(0); // Graceful pause}Pattern: Hot Reload via Watch
Subscribe to a document and react to every change without a restart. Watch is available in the Node, Browser and Go SDKs and is delivered over WebSocket. It is the one config operation the Python SDK does not have.
const watcher = config.watch("worker-settings", { onUpdate: (event) => { applyRuntimeConfig(event.data); }, onError: (err) => console.error("config watch error:", err),});
// Later — stop watching during graceful shutdownwatcher.stop();Pattern: Discovery & Cleanup
Use list() to enumerate every config document in the current environment, and delete() to remove a stale one.
const docs = await config.list();for (const doc of docs) { console.log(doc.name);}
await config.delete("legacy-flags");Best Practices
- Environment Scoping is Automatic: The server derives the environment from the API Key on the request. There is no environment header to pass — use a different API Key per environment to target dev / staging / production.
- Shallow Merge: Prefer
patch()overset()for runtime updates to prevent accidentally overwriting keys set by other team members or processes.patch()also creates the document if it does not yet exist. - Validation: Perform schema validation in your application logic after calling
get(), as the Config Store accepts any valid JSON.