- State & Storage
- Config Patterns
Config Patterns
Patterns & Best Practices
Section titled “Patterns & Best Practices”Config vs KV Store
Section titled “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
Section titled “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. Pass
if_none_match="*" for create-if-absent. Config watch is client.watch_config;
see the hot-reload pattern below.
Pattern: Application Settings
Section titled “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}settings = client.config_get("worker-settings")
if settings["data"].get("maintenanceMode"): sys.exit(0) # Graceful pausePattern: Hot Reload via Watch
Section titled “Pattern: Hot Reload via Watch”Subscribe to a document and react to every change without a restart. Watch is available in the Node, Browser, Go and Python SDKs and is delivered over WebSocket.
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();watcher, err := client.Config().Watch(ctx, "worker-settings", ironflow.ConfigWatchCallbacks{ OnUpdate: func(event ironflow.ConfigWatchEvent) { applyRuntimeConfig(event.Data) // nil after the config is deleted }, OnError: func(err error) { log.Println("config watch error:", err) },})if err != nil { log.Fatal(err)}// Later — stop watching during graceful shutdowndefer watcher.Stop()# Needs the watch extra: pip install 'ironflow-py[watch]'from contextlib import aclosing
async with aclosing(client.watch_config("worker-settings")) as events: async for event in events: apply_runtime_config(event.data)# Leaving the block stops watching. A watch error raises IronflowError.Pattern: Discovery & Cleanup
Section titled “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");for doc in client.config_list()["configs"]: print(doc["name"])
client.config_delete("legacy-flags")Best Practices
Section titled “Best Practices”- Environment Scoping is Automatic: The server derives the environment from the API Key on the request. An
X-Ironflow-Environment-IDheader (the GoClientConfig.Environmentoption sends one) that names another environment returns403. 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.