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
Design principle. Treat every default as production behavior — not as a placeholder. The default is what your application does when SOASAP cannot supply a valid value. Code review should ask: "Is this default safe if Production runs with it for an hour?"

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

  1. Application code calls a getter with a flag key and an explicit default
  2. The SDK reads from the current in-memory snapshot — O(1), no network I/O
  3. If the key exists and the type matches, the stored value is returned
  4. 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