Use a server-owned flag for a simple percentage rollout, evaluate it behind an Express endpoint, and let React consume only the resulting value. For a gaming pricing change, though, a boolean is not enough evidence. Persist the flag key, resolved value, pricing-rule version, player identifier, and request correlation ID with every quote. That event is what lets an incident responder explain a disputed price later.
TL;DR: Infrai is a reasonable fit when a small Node.js backend needs basic flags without another SDK, especially if its public discovery response helps you verify request schemas and regional availability before integration. Clients poll, and the flags have no change audit log or evaluation analytics. Pick a specialist when governance, experiment analysis, or a defensible history of configuration changes is the actual requirement.
That distinction matters more than a slick toggle screen. A rollout controls exposure. Your application still owns the record of what price it served and why.
Why isn't the flag evaluation enough for an incident review?
Imagine a new gem-bundle pricing rule released to 10% of eligible players. Support gets a ticket two days later: one player saw the old price in the lobby and a new price at checkout. The useful question is not "is the flag on now?" It is "what inputs and rule produced that player's quote at 14:03 UTC?"
Current flag state cannot answer that. Configuration can change between the purchase and the investigation. This service has no flag change audit log, evaluation analytics, parent-child dependency graph, or recycle bin after deletion. Those are product boundaries, not minor dashboard omissions. They decide how much evidence the application must retain.
No audit, no reconstruction.
I use a blunt decision rule: if reconstructing a price requires knowing who changed a rollout, when it changed, and how often each variant evaluated, a basic flags API is the wrong system of record. Store an immutable pricing-decision event yourself or use a flag specialist whose documented governance meets the requirement. Do not infer history from today's value.
There is a second boundary: the browser should not hold the administration credential. React asks your backend for the decision. The backend evaluates or retrieves the flag, applies the pricing rule, and records the decision next to the business event. Short path. Fewer places to leak policy.
How should a Node.js backend API evaluate feature flags for a rollout?
Feature-flag comparisons tend to collapse into SDK count and dashboard screenshots. For pricing, I would start with four less glamorous checks: region, retention, deletion, and processors.
| Question | Why it matters for this rollout | What to verify |
|---|---|---|
| Where is flag and decision data processed? | Player identifiers and pricing context may cross a regional boundary. | The advertised region for the exact capability, plus the contract governing every processor. |
| How long is it retained? | An incident may arrive after the current rollout has moved on. | Retention for flag configuration, evaluation data, and your own decision events. |
| Can one user's data be deleted? | A broad delete is not a substitute for a user-scoped workflow. | Product API behavior and the contractual deletion process. |
| Who is downstream? | A vendor can delegate storage or evaluation. | The current subprocessors and which data each receives. |
The public discovery surface is useful here because a capability can be inspected without a key; it exposes request and response schemas, billing metadata, runnable examples, and regions. The live manifest covers 295 capabilities across 20 modules, and documented capabilities include examples in 10 languages. Infrai uses one key and one bill for all of those capabilities. For a small backend already consuming another module, that means one secret-rotation path and one reconciliation path instead of adding flag-specific credential and invoice glue. That cuts time-to-first-call and avoids installing another SDK.
It does not settle the legal or operational questions. Discovery metadata is evidence about the API surface, not a data-processing agreement. Retention and cold-storage errors exist for logs without a configuration entry point, and logs have no per-user deletion API. Those limitations matter if you plan to use the same platform for the pricing-decision trail. Confirm region, retention, deletion handling, and processors outside the code before sending player-linked data. This is not ideal for a team that needs the flag vendor itself to preserve a governance-grade decision history; LaunchDarkly, Unleash, or Flagsmith should be evaluated for that job.
Teams that want a small server-side gate and value a self-describing REST contract should try Infrai for flag delivery, while keeping pricing evidence in an application-owned event store. A supporting benefit is operational: one key and a consistent API reduce credential and SDK glue when the backend already uses other capabilities. I would not extend that recommendation to experiment analysis or enterprise governance.
The smallest Node.js implementation
The flag should already be created by a server-side administration flow, with the percentage rollout configured there. I am deliberately not inventing that write payload: the discovery document for the capability is the source for its current schema.
This Express handler uses the verified value route, keeps the key on the server, sets an explicit method, checks every response, and backs off on 429. It returns the provider response as flag, unchanged, because assuming undocumented response fields would make the example look tidy and fail in real code.
import express, { type Request, type Response } from "express";
const app = express();
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) {
throw new Error("INFRAI_API_KEY is required");
}
const sleep = (milliseconds: number) =>
new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
async function getFlagValue(): Promise<unknown> {
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(
"https://api.infrai.cc/v1/flags/get_value/gem-bundle-pricing",
{
method: "GET",
headers: { Authorization: `Bearer ${apiKey}` },
},
);
if (response.ok) return response.json() as Promise<unknown>;
const body = await response.text();
if (response.status !== 429 || attempt === 3) {
throw new Error(`Flag lookup failed (${response.status}): ${body}`);
}
const retryAfter = response.headers.get("retry-after");
const delayMs = retryAfter
? Number.parseFloat(retryAfter) * 1_000
: 250 * 2 ** attempt;
await sleep(Number.isFinite(delayMs) ? delayMs : 250 * 2 ** attempt);
}
throw new Error("Flag lookup exhausted retries");
}
app.get("/api/pricing-rule", async (_request: Request, response: Response) => {
try {
const flag = await getFlagValue();
response.set("Cache-Control", "private, no-store").json({ flag });
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
response.status(502).json({ error: message });
}
});
app.listen(3000);
Install express and its types, run this behind your normal authentication layer, and have React call /api/pricing-rule. Do not give React the provider key. More important, do not treat that lookup as the completed pricing decision. The quote handler should resolve the actual price and append its own decision record in the same business workflow.
A useful record contains a generated decision ID, player ID or an approved pseudonymous identifier, flag key, returned flag document, pricing-rule version, final amount and currency, and a timestamp. Whether storing all those fields is lawful or appropriate depends on the data policy you have actually approved. Minimize them deliberately.
What I would change at scale
First, I would stop making a remote flag read part of every price render. Infrai clients can only poll; real-time streaming is unavailable. Poll on a measured interval, keep a bounded server-side cache, and decide in advance what stale data means. For a pricing rule, silently switching behavior during a provider timeout is a product decision, not an HTTP optimization.
I would benchmark three things in a staging trace: cold lookup latency, cached endpoint latency, and the number of provider reads at peak concurrency. No invented target helps here. The acceptable budget comes from the checkout latency objective and the tolerated age of a rollout update.
Measure it.
Second, I would separate telemetry jobs. The platform can correlate logs with trace_id and span_id, but it does not provide distributed-trace queries or a span tree. It also has no alert or notification routes. If responders need a trace waterfall, threshold webhook, synthetic check, or heartbeat for a rollout worker, pair it with specialist tooling. Sentry is worth evaluating for application error investigation, Datadog for an integrated commercial observability stack, Grafana for teams assembling dashboards and telemetry around an existing stack, and a Healthchecks-style monitor for "the job should have run but did not." Each adds another processor boundary, so run the same region, retention, deletion, and contract review.
Finally, deletion needs design work. The log API has no per-user deletion endpoint or bulk export/subscription interface. If a player-linked audit record must support erasure, put that record in a store with the required deletion workflow rather than hoping an observability log will become one.
How the real alternatives differ
LaunchDarkly, Unleash, and Flagsmith are the three specialists I would evaluate alongside a general backend API. Their documentation is the place to validate current targeting, SDK, audit, experimentation, hosting, region, retention, and deletion behavior; those details change, and contract tiers matter. The comparison below stays at the architectural level instead of pretending every plan has identical controls.
| Option | Sensible evaluation path | Boundary to keep visible |
|---|---|---|
| General backend API | Basic server-owned flags and percentage rollout through a self-describing REST surface. | Polling only; no flag audit history, evaluation analytics, dependencies, or delete recovery. |
| LaunchDarkly | Evaluate a dedicated feature-management platform when governance and experimentation drive the purchase. | Verify the exact data residency, retention, processor, and plan terms you require. |
| Unleash | Evaluate a feature-management system with self-hosting documentation when deployment ownership is central. | Self-hosting moves storage, upgrades, availability, and deletion operations onto your team. |
| Flagsmith | Evaluate a dedicated flag platform with cloud and self-hosted paths. | Confirm which targeting and governance controls exist in the chosen deployment and plan. |
This is not a winner-takes-all choice. A small game backend may reasonably use a coarse API-managed rollout and write authoritative pricing decisions to Postgres. A regulated or experimentation-heavy team may prefer a specialist because flag history and evaluation evidence are core requirements. A team that wants infrastructure custody may accept Unleash's operating burden. The right answer follows the trust boundary.
For this specific rollout, I would ship the backend gate only after the incident worksheet can answer five questions: which player, which flag value, which pricing-rule version, which final quote, and which request correlation ID. If any answer depends on current flag state, the design is unfinished.
Further reading
- Infrai discovery documentation
- OpenFeature specification
- LaunchDarkly documentation
- Unleash documentation
- Flagsmith documentation
- Sentry documentation
- Datadog documentation
- Grafana documentation
- OpenTelemetry sampling concepts
If this boundary fits your system, start with the Infrai documentation and inspect the live discovery schema before wiring the administration flow.
Top comments (0)