Default Values
Code-defined fallbacks used when a flag is unavailable, missing, invalid, or not yet synchronized.
Introduction
Every SOASAP flag evaluation requires a default value. The default is defined in application code — not in the dashboard — and represents the behavior your application should use when a valid flag value cannot be returned from the local SDK snapshot.
Examples:
.NET
flags.GetBool("new-checkout", defaultValue: false);
Node.js
flags.getBool("new-checkout", false);
Python
flags.get_bool("new-checkout", False)
The same rule applies to every getter — GetString,
GetNumber, GetJson, and their equivalents
in other SDKs. Defaults are mandatory parameters, not optional convenience arguments.
SOASAP getters never throw on evaluation failures. When the SDK cannot return a valid value, it returns your default silently. That design makes defaults the contract for safe runtime behavior.
Why default values exist
Feature flags are configuration. Configuration can be:
- Missing — the key was never created or is absent from the synchronized snapshot
- Deleted — the flag was removed from the project or disabled in an environment
- Invalid — the stored type does not match the getter, or JSON deserialization fails
- Temporarily unavailable — synchronization has not completed, cache is empty, or the network is down
Applications must continue operating safely in these situations. Default values ensure deterministic behavior without exceptions, retries, or blocking network calls on the request path.
In SOASAP's local-first model, flag reads never contact SOASAP Cloud. There is no runtime fallback to a remote API when a key is missing — your code default is the fallback.
When default values are used
The SDK returns your explicit default when any of the following conditions apply:
Missing flag
The flag key does not exist in the synchronized snapshot for the bound environment.
flags.GetBool("new-checkout", defaultValue: false);
Result:
false
Deleted flag
The flag existed previously but was removed from the dashboard or disabled for the environment. The SDK snapshot no longer contains the key. Evaluation returns the code default until a new definition syncs — if ever.
First startup
The application starts before the first SSE payload arrives. On cold start, the SDK may hydrate from a persistent cache; if no cache exists, all reads return defaults until synchronization completes.
On React Native, AsyncStorage hydration is asynchronous — reads may return defaults for a brief period even when a cached snapshot exists on disk. See AsyncStorage Cache.
Empty cache
No local snapshot is available — first deploy on a new machine, cleared browser storage, or invalid cache file. The SDK continues in memory-only mode and returns defaults until the first successful sync. See Persistent Cache.
Invalid type
Dashboard value type does not match the getter:
Dashboard:
checkout-theme = "dark"
Code:
flags.GetBool("checkout-theme", defaultValue: false);
Result:
false
Type mismatches never throw — the SDK returns the default you provide.
Synchronization delay
The dashboard was updated but the SDK has not yet received the SSE payload. Reads continue using the last known snapshot or your default if no snapshot exists. Propagation is typically sub-second on healthy networks; during delay, stale values or defaults apply — never blocking waits.
Production safety
Default values are the primary safety mechanism in SOASAP. Applications should never assume that configuration is always available, current, or correctly typed.
A well-chosen default ensures predictable behavior during:
- Deployments — new processes start before SSE connects; cache may or may not exist
- Cold starts — first request may read defaults or stale cache before live sync
- Outages — SOASAP Cloud or network unavailable; reads use last snapshot or defaults
- Synchronization delays — dashboard change not yet reflected in the local snapshot
- Configuration mistakes — wrong type, typo in key, or flag deleted accidentally
See Production Safety.
Choosing good defaults
Defaults should reflect the safest outcome for each flag's purpose.
Feature releases
flags.GetBool("new-checkout", defaultValue: false);
Recommended: false. New functionality remains disabled unless explicitly enabled in the dashboard.
Kill switches
flags.GetBool("disable-payments", defaultValue: false);
Recommended: false for flags named after the failure action. The system remains operational unless intentionally disabled from the dashboard.
Maintenance mode
flags.GetBool("maintenance-mode", defaultValue: false);
Recommended: false. Applications remain available by default; maintenance is an explicit operator action.
Numeric limits
Choose conservative values — lower limits, shorter timeouts, smaller batch sizes.
flags.GetNumber("max-items", defaultValue: 10);
Validate and clamp after read. SOASAP does not enforce min/max bounds — your default and validation logic define safe limits.
String variants
flags.GetString("checkout-mode", defaultValue: "standard");
Default to the current production-certified variant, not an experimental path.
JSON configuration
Provide a complete safe object — every field populated with conservative values.
flags.GetJson(
"checkout-config",
new CheckoutSettings
{
Enabled = false,
TimeoutSeconds = 30,
MaxItems = 10,
});
Avoid empty objects or partial defaults that force null-checks throughout the codebase.
Bad defaults
Defaults must be intentional. Avoid patterns that enable risky behavior or hide misconfiguration.
Enabling features by default
flags.GetBool("new-checkout", defaultValue: true);
Only use true when enabling the feature is genuinely the safest outcome —
for example, a flag that gates removal of legacy code where the new path is already the only
safe production path. For new feature releases, prefer false.
Null or empty references
flags.GetJson<CheckoutSettings>("checkout-config", defaultValue: null);
Nullable defaults propagate null-checks to every call site and increase the risk of
NullReferenceException or equivalent runtime errors.
Provide a fully constructed default object instead.
Zero when zero is dangerous
flags.GetNumber("http-timeout-ms", defaultValue: 0);
Zero may mean "no timeout", "unlimited batch", or "disabled retry" depending on context. Choose a default that represents valid production behavior, not the numeric zero literal by habit.
Empty strings for required modes
flags.GetString("payment-provider", defaultValue: "");
An empty string rarely represents safe routing behavior. Default to a known production provider or a named fallback mode, and validate unrecognized values after read.
Runtime behavior
- Application code calls a getter with a flag key and an explicit default
- The SDK reads from the current in-memory snapshot — O(1), no network I/O
- If the key exists and the type matches, the stored value is returned
- If the key is missing, mistyped, or invalid, the code default is returned
Default evaluation is entirely local. No network requests are performed. No exceptions are thrown. No retries occur on the request path. Background SSE synchronization updates the snapshot independently; the next read may return the synchronized value without any change to your default parameter.
See Local Evaluation.
Common mistakes
Unsafe defaults
Defaulting feature gates to true, limits to unbounded values, or
JSON configs to fully enabled states means a missing flag silently enables risky behavior.
Defaults should fail safe.
Inconsistent defaults across the codebase
Reading the same key with false in one service and
true in another produces inconsistent behavior during outages
or before sync. Centralize defaults in constants or shared configuration helpers.
Undocumented defaults
Future maintainers cannot tell whether false was chosen deliberately
or copied from a template. Document non-obvious defaults in code comments or team runbooks —
especially for kill switches and operational limits.
Defaults that hide configuration problems
If Production silently runs with defaults identical to enabled features, a misconfigured API key
or deleted flag may go unnoticed. Log or monitor background SDK errors via
onError / OnError handlers;
do not rely on defaults alone to surface dashboard mistakes.
Omitting the default parameter
Some SDK hooks and signal helpers provide built-in defaults (false,
0, ""). Treat these as convenience
only — always pass an explicit default at call sites that control production behavior so intent
is visible in code review.
Best practices
- Always provide explicit defaults — every getter call in production paths should pass a code-defined fallback; never rely on implicit behavior.
- Prefer safe defaults — disabled features, conservative limits, and certified variants; assume the default may run for extended periods during outages.
- Keep defaults consistent — one canonical default per flag key across services, shared via constants or helper methods.
- Document important defaults — explain why a non-obvious value was chosen, especially for kill switches, limits, and JSON config objects.
- Review defaults during code review — treat defaults with the same scrutiny as business logic; ask whether they are safe under outage and cold-start conditions.
- Treat defaults as part of production behavior — they define what the application does when SOASAP cannot help; they are not secondary or temporary.
Related documentation
- Boolean Flags — on/off toggles and recommended Boolean defaults
- String Flags — text variants and default strings
- Number Flags — numeric limits and conservative defaults
- JSON Flags — complete default objects for structured config
- Architecture — local evaluation and snapshot reads
- Offline Operation — behavior when sync is unavailable
- Persistent Cache — cold starts and cache hydration
- SDK Documentation — install and configure your platform SDK