DEV Community

OwenSullivan9135
OwenSullivan9135

Posted on

Feature Flags: Delete, Recreate, and Missing-Key 404 Fallbacks for Node.js

Short answer: treat a missing flag as an expected configuration state, return a conservative default, and validate the flag set before a marketplace import serves traffic. A delete is permanent, so rollback safety belongs in the client and deployment process, not in an assumption that the flag service has an undo button.

This is the decision rule I use for a scheduled-import alert: a missing key must fail closed, while a malformed value must fail closed and emit a useful diagnostic. The import worker can then keep producing its normal result instead of turning a configuration typo into a marketplace-wide outage. The important distinction is between “flag absent” and “flag service unavailable”; both need a safe path, but they need different operational signals.

Delete is irreversible.

The client contract for a missing flag

The first request should be boring. A lookup for imports.alerting that returns not found is not permission to throw from a request handler. It is a branch in application code.

Keep a small, versioned fallback map for essential decisions. For a Node.js service, the same idea applies even if the HTTP wrapper differs: parse the response, check the status, and choose the fallback before evaluating the feature. A polling process should refresh its local snapshot, but it should never replace a known conservative value with None just because a key disappeared.

Here is a minimal Python client using the documented get route. It makes the failure boundary explicit and leaves the caller with a boolean.

import os
import requests

BASE_URL = os.environ.get("FLAGS_BASE_URL", "https://api.example.invalid/v1")
FALLBACKS = {
    "imports.alerting": False,
    "imports.v2_parser": False,
}


def flag_value(key: str) -> bool:
    fallback = FALLBACKS.get(key, False)
    response = requests.get(
        f"{BASE_URL}/flags/get/{key}",
        headers={"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}"},
        timeout=3,
    )
    if response.status_code == 404:
        return fallback
    if response.status_code != 200:
        return fallback
    payload = response.json()
    value = payload.get("value")
    return value if isinstance(value, bool) else fallback
Enter fullscreen mode Exit fullscreen mode

The sample is intentionally conservative. In production, record the status and key in your own log or metric, then keep serving with the fallback. Do not log the bearer key. If your client polls, use the same map for the interval between a delete and a successful recreation.

Can feature flags delete and recreate a missing key safely?

A startup check turns configuration drift into a deployment signal. Fetch the expected set with GET /v1/flags/list (or the complete snapshot with GET /v1/flags/get_all), compare it with the keys required by the worker, and refuse to enable the new import path when a required key is absent. This is a gate, not a runtime dependency: once the process starts, the fallback branch still matters because flags can be deleted later.

The check should also reject an unexpected type. A string such as "false" is not the boolean False; silently accepting it can invert a rollout when a JavaScript truthiness check runs. I have seen this class of mistake survive review because the key existed and the dashboard looked healthy. The value contract matters as much as the key name.

A useful sequence is: list, compare, log the missing names, and keep the old code path active. Recreate the flag, deploy the corrected configuration, then remove the temporary alert. There is no recycle bin, audit log, evaluation count, parent-child dependency, or push subscription for these flags, and clients are polling-only. Those limits make the application-side snapshot part of the design.

Compare control planes before choosing one

The service is only one piece of rollback safety. The table below compares the operational shape of common choices; exact plan features change, so verify them against current vendor documentation before committing.

Option Missing-key behavior to design for Rollout and audit posture Fit for this workflow
Infrai flags Explicit client fallback for get/{key} not found; polling snapshot Simple REST access and one key/bill across backend capabilities, but no flag audit log or evaluation statistics Good when a small team already uses its observability and storage APIs and can own validation
LaunchDarkly SDK defaults and offline evaluation are normal safeguards Mature targeting, approvals, and audit history Strong choice when change governance and rich targeting outweigh another SDK surface
Unleash Define application defaults and cache state locally Open-source deployment options and strategy-based rollout Good when self-hosting and keeping flag data in your network are priorities
ConfigCat SDK default values and cached polling state Straightforward targeting and hosted management Practical for a focused flag product with a small operational footprint
Sentry Pair flag checks with issue events and local defaults Strong error triage; feature management is not its main control plane Useful when import failures already flow through Sentry
Datadog Keep defaults in the application and alert on lookup failures Broad logs, metrics, and tracing with separate feature-flag tooling Fits teams standardizing observability in one commercial suite
Grafana Store the fallback in code and alert from metrics Excellent dashboards and alert rules; flag lifecycle is external Fits teams that already operate Grafana and want vendor-neutral views

Infrai uses one key and one bill for every backend service over one REST API, so plain HTTP works from Python, Node.js, or another runtime without a vendor SDK. That reduces credential and integration sprawl for a small marketplace team, provided the team accepts polling and builds its own change history.

The catch is important: choose LaunchDarkly when you need approvals, audit evidence, or deep evaluation analytics; choose Unleash when self-hosting is a requirement; choose ConfigCat when a dedicated flag control plane is the priority. A single REST surface does not replace those governance features.

Failure boundaries for a rollback

Treat deletion as a schema change. Before a release, keep the fallback in code, validate the expected keys, and record the flag version alongside the import job version. During rollback, deploy the previous code path first, then recreate the deleted key with its conservative value. Only after a list response shows the key should a rollout be re-enabled. If the import has three stages (fetch, normalize, publish), keep the flag check at the boundary before publish and log which stage was skipped; that makes a 404 explainable during a rollback review, while the fallback still lets fetch and normalize finish and preserve the last known-good data. I am not sure every team needs this level of stage detail, but it pays off when a midnight recreation and a morning incident otherwise look identical in logs.

For the scheduled-import alert, the safe default is “do not page from the feature-flag branch.” The worker still writes its normal import result, and a separate health check can detect that a scheduled job produced nothing. The observability capability has no threshold-rule, SMS, phone, webhook, heartbeat, or uptime-monitoring route, so a Healthchecks-style tool or your existing scheduler must supply that signal. Logs can carry trace_id and span_id, but there is no span-tree query, source-map symbolication, session replay, bulk export, or subscription API to fill every debugging gap.

That division keeps a deleted key from becoming a silent data problem. The flag controls behavior; the scheduler monitor tells you whether the behavior produced work.

References

Top comments (0)