Feature Flags and Configuration
A feature flag turns a feature on or off at runtime, without a deploy. Runtime configuration changes values such as limits or timeouts in the same way. When many instances of a service read the same flag, they must all see the same value, and a bad change must be easy to find and undo.
Kahuna can store feature flags and runtime configuration with strong consistency, revisions, compare-and-set updates, and historical snapshot reads.
Use a predictable key layout:
config/{environment}/{service}/{name}
Examples:
config/prod/payments/max-refund-amount
config/prod/search/enable-new-ranking
Read a Flag
- .NET
- TypeScript
KahunaKeyValue flag = await client.GetKeyValue(
"config/prod/search/enable-new-ranking",
KeyValueDurability.Persistent
);
bool enabled = flag.Success && flag.ValueAsString() == "true";
const flag = await client.get("config/prod/search/enable-new-ranking", {
durability: "persistent"
});
const enabled = flag.success && flag.valueAsString() === "true";
Update Safely With Compare Revision
Read the current revision, then update only if nobody changed it first:
- .NET
- TypeScript
KahunaKeyValue current = await client.GetKeyValue(
"config/prod/search/enable-new-ranking",
KeyValueDurability.Persistent
);
KahunaKeyValue updated = await client.TryCompareRevisionAndSetKeyValue(
"config/prod/search/enable-new-ranking",
"true",
compareRevision: current.Revision,
durability: KeyValueDurability.Persistent
);
if (!updated.Success)
Console.WriteLine("Flag changed before this update was applied.");
const current = await client.get("config/prod/search/enable-new-ranking", {
durability: "persistent"
});
const updated = await client.compareRevisionAndSet(
"config/prod/search/enable-new-ranking",
"true",
current.revision,
{ durability: "persistent" }
);
if (!updated.success) {
console.log("Flag changed before this update was applied.");
}
Read Historical Configuration
Use LastModified from one read as a snapshot anchor:
- .NET
- TypeScript
KahunaKeyValue anchor = await client.GetKeyValue(
"config/prod/search/enable-new-ranking",
KeyValueDurability.Persistent
);
List<KahunaKeyValue> configAtAnchor = await client.ScanAllByPrefix(
"config/prod/search",
KeyValueDurability.Persistent,
snapshotMs: anchor.LastModified
);
const anchor = await client.get("config/prod/search/enable-new-ranking", {
durability: "persistent"
});
const configAtAnchor = await client.scanAllByPrefix("config/prod/search", {
durability: "persistent",
snapshotMs: anchor.lastModified
});
This is useful during incident review when you need to know which flags and settings were visible at one point in time.
Group Related Settings
For settings that should be read together, use one bucket:
get by bucket `config/prod/search`
From a client:
- .NET
- TypeScript
List<KahunaKeyValue> settings = await client.GetByBucket(
"config/prod/search",
KeyValueDurability.Persistent
);
const settings = await client.getByBucket("config/prod/search", {
durability: "persistent"
});
Operational Notes
- Use persistent durability for production configuration.
- Use compare-revision updates in admin tools to avoid lost updates.
- Keep values compact and parseable, for example JSON for structured settings.
- Use snapshot reads during postmortems to reconstruct the exact configuration that was visible at the time.