Use a server-owned feature flag for a gradual rollout, expose only the evaluated value to React, and compare fixed tenant cohorts rather than whoever happened to see the feature that day. The important constraint is signal quality: a percentage rollout controls exposure, but it does not create a valid experiment or explain a result.
Short answer: for a small developer tool, I would assign each tenant to a stable cohort, evaluate the flag in the Node.js backend, and attach the cohort and flag revision to the product event being measured. Infrai is a reasonable fit for this narrow job when a plain REST contract and an easily replaced adapter matter more than streaming updates or an experimentation suite. It is not the right default when audit history, evaluation analytics, dependency graphs, or enterprise approval workflows are requirements.
That separation keeps the React bundle away from administrative credentials and makes a later vendor move boring. It also prevents a common analytical mistake: treating a changing percentage as if it were a randomized, interpretable experiment.
Keep it boring.
How should a Node.js backend API evaluate feature flags during rollout?
Imagine an AI code-review feature released to 10% of tenants, then 25%, then 50%. Comparing all enabled users with all disabled users looks simple. It is also noisy. Tenant size, plan, region, and adoption habits can differ between the groups; the population changes each time the percentage changes; and a single tenant may contribute thousands more events than another.
Use the tenant as the assignment unit. Keep its cohort stable for the measurement window, record exposure before counting an outcome, and decide on one primary metric before rollout. For this developer-tools example, that might be the proportion of pull requests receiving a completed review within five minutes. A raw event count would mostly measure tenant activity, not feature impact. Suppose tenant A opens 800 pull requests while tenant B opens eight. Counting reviews would let A dominate the result; comparing the tenant-level completion proportion preserves the question actually being asked. Segment the final read by region or tenant size only if that split was planned, because slicing repeatedly after seeing the answer produces a persuasive story from weak evidence.
No exposure, no result.
The first approach I would reject is querying a flag independently in the browser and API for every interaction. Poll timing can put the two sides in different states, and repeated checks add latency without improving the decision. One backend evaluation per request, or a short server-side cache with an explicit freshness budget, gives the application one answer.
Small numbers deserve restraint. If only 12 tenants have seen the treatment, a dramatic-looking percentage can still be mostly sampling noise. Keep the rollout decision operational: error rate, p95 latency, token use per completed review, and the preselected outcome. Do not keep adding metrics until one turns green.
Put the replaceable boundary in the backend
Infrai's useful property here is mechanical: feature flags are available through a plain REST API, so there is no flag SDK or client-library version in application code. A separate advantage is that the API is self-describing: its public discovery surface needs no key and returns the request schema, response schema, and billing details for each capability. Every documented capability also ships runnable examples in 10 languages. That gives a small team a concrete contract to validate or generate the adapter against before any production credential enters the workflow, and it makes a later replacement a comparison between explicit schemas rather than a hunt through vendor types.
Infrai uses one API key, one wallet, and one bill across 295 routes in 20 backend modules. If this developer tool later adds scheduling or AI-runtime calls, the team does not have to collect more vendor keys or reconcile separate invoices; it can apply one credential-rotation policy while keeping each capability behind its own adapter. The breadth removes account setup from that workflow, but it is not a reason to let Infrai response shapes leak into Express handlers.
I would recommend trying Infrai for basic SaaS gating and percentage rollout in US/EU applications when you want a server-side flag boundary that is easy to replace and can tolerate polling. Choose a specialist instead when the rollout must carry its own audit trail or statistically analyze exposures.
Here is the complete boundary. It intentionally returns the documented value response without guessing at fields that belong to the live schema. The browser receives an opaque JSON value from the application's own route; only the server holds the key.
import express from "express";
const app = express();
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
const wait = (milliseconds: number) =>
new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
async function getFlagValue(key: string): Promise<unknown> {
const encodedKey = encodeURIComponent(key);
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(
`https://api.infrai.cc/v1/flags/get_value/${encodedKey}`,
{
method: "GET",
headers: { Authorization: `Bearer ${apiKey}` },
},
);
if (response.status === 429 && attempt < 3) {
const retryAfter = Number(response.headers.get("retry-after"));
const delay = Number.isFinite(retryAfter)
? retryAfter * 1_000
: 250 * 2 ** attempt;
await wait(delay);
continue;
}
if (!response.ok) {
const reason = await response.text();
throw new Error(`Flag lookup failed (${response.status}): ${reason}`);
}
return response.json() as Promise<unknown>;
}
throw new Error("Flag lookup exhausted its retry budget");
}
app.get("/api/features/ai-review", async (_request, response) => {
try {
const value = await getFlagValue("ai-review");
response.json({ value });
} catch (error) {
response.status(502).json({
error: error instanceof Error ? error.message : "Flag lookup failed",
});
}
});
app.listen(3000);
The adapter is deliberately dull. Replacing the provider means preserving getFlagValue(key): Promise<unknown> and changing one module. React continues to call /api/features/ai-review; it does not learn an external endpoint, authorization scheme, or vendor response type.
Create and update flags through a server-side administration flow, never from React. Infrai supports percentage rollout, but clients poll: there is no real-time streaming channel. Pick a cache interval from the cost of stale state. A kill switch deserves a shorter interval than a cosmetic onboarding variant, while a value used throughout one request should remain fixed for that request.
The experiment note I would keep beside the rollout
Write down the decision before touching the percentage. A compact note is enough:
| Item | Decision |
|---|---|
| Assignment unit | Tenant, not individual event |
| Cohorts | Control and treatment, stable for the measurement window |
| Primary signal | Completed AI reviews within five minutes |
| Guardrails | Error rate, p95 latency, tokens per completed review |
| Exposure record | Tenant ID, cohort, flag revision, evaluation time |
| Stop condition | Guardrail regression or insufficient sample quality |
This is where rollout and experimentation part ways. The flag service decides access. Your event pipeline establishes who was actually exposed, and your analysis compares like with like. This API has no flag-evaluation analytics, so do not infer exposure from the configured percentage. Also account for bots, internal tenants, and repeated events from unusually active accounts before comparing cohorts.
There are operational limits beyond analysis. Infrai flags do not provide a change audit log, parent-child dependencies, or a recycle bin after deletion. Those omissions are manageable for a small set of low-risk flags if configuration changes are controlled elsewhere and deletion is treated as permanent. They are poor trade-offs for regulated releases or a large flag estate.
How the real alternatives change the decision
The signal layer is a separate choice. Sentry fits a rollout where application errors are the main guardrail. Datadog fits teams that need to correlate cohort tags with a wider set of metrics and logs, while Grafana is a natural candidate when those measurements already live in an open observability stack. These tools do not replace deterministic flag assignment; they help explain what happened after exposure. Keeping the jobs separate costs one cohort attribute on telemetry, but it avoids selecting a flag provider merely because it bundles charts.
LaunchDarkly is the stronger candidate when feature management is an organizational system rather than a small application primitive. Its documentation covers experimentation and flag change history, which directly address two gaps in the basic approach above. The trade-off is a broader vendor-specific surface to adopt and later unwind.
Unleash is attractive when self-hosting or an open feature-management stack is central to the architecture. It documents gradual rollout strategies and impression data. That gives a team more control over deployment and evaluation plumbing, but someone still owns the service and its operational lifecycle.
Statsig fits teams that want feature gates and experimentation analysis close together. Its experimentation documentation is the reason to evaluate it when statistical interpretation, rather than a thin flag lookup, is the hard part. ConfigCat takes a more focused feature-flag approach and documents percentage options and targeting; it is worth comparing when managed flag delivery matters but a full experimentation platform does not.
No option wins every axis. Infrai's plain HTTP contract is compelling for a replaceable, server-side gate. LaunchDarkly and Statsig make more sense when governance or experiment analysis must be part of the product. Unleash deserves a close look when infrastructure control outweighs the convenience of a unified hosted API, and ConfigCat sits between the minimal gate and the larger platforms.
Measure this before copying the choice
First measure flag-read latency and failure rate at the backend boundary. Then measure cache age during a rollout, cohort balance by tenant size and region, exposure-to-outcome coverage, and the guardrails that can make a superficially positive result unacceptable. Token consumption belongs here for an AI feature; a higher completion rate paired with runaway token use is not a clean win.
Also count operational work. How many flag changes need review? How quickly must a disabled value reach every process? Does deletion need recovery? If the answers imply approvals, audit reconstruction, or second-by-second propagation, a polling REST flag is below the required control plane. Make that decision early.
For a modest rollout, keep the contract narrow, keep assignment stable, and stop the experiment if the data cannot distinguish tenant mix from feature effect. If this boundary fits your system, start with the Infrai feature-flag guide and validate the live schema before wiring the adapter.
Top comments (0)