Server-Side vs Client-Side Feature Flags: Choosing the Right Boundary
Same flag. Same key. Move a decision from backend-only code to client-visible UI and you've changed its latency, its exposure, and how carefully the browser and server need to stay in sync.
Most teams pick a flag boundary by accident — whichever SDK they grabbed first — and only discover the trade-offs when a UI hides a button that the API still accepts, or a backend blocks a feature the browser just showed. It's worth deciding on purpose.
What "Client-Side" Actually Means
Server-side evaluation happens inside your backend. The SDK holds your targeting rules in memory, evaluates the flag against a user context, and returns a value in microseconds — no network round trip per check. The browser only ever sees the result.
Client-side flags are consumed by the browser or mobile app, but with Featureflow the flag is not generally evaluated there. The client sends its user context to Featureflow, Featureflow evaluates the rules server-side, and the client receives evaluated flag values it can use to render the UI.
That distinction matters. Client flags are good for hiding, showing, or changing UI. They are not a replacement for server checks on sensitive endpoints, write paths, pricing, permissions, or anything that must be enforced regardless of what the browser sends.
The Three Trade-Offs That Matter
Secrecy. A client-side flag value is visible to the client because the UI needs it. If a flag protects an unreleased feature, an acquisition codename, or pricing and permission logic, keep the enforcement server-side. The browser can hide the surface area; the server must still own the decision.
Latency and caching. Server-side evaluation is local and effectively free per check. Featureflow client flags are designed for fast delivery too: evaluated values are served through a global CDN, and most rule evaluation stays server-side so clients do not need the full rule set.
Coordination. A client-side flag can hide a button instantly, but the server endpoint behind that button still needs the same protection. A bad rollout is easier to recover from when both sides use the same flag key and the same user context, so UI and API behaviour change together.
There is one smart exception in Featureflow's client model: datetime-based rules can be evaluated on the client. That keeps caches useful because every evaluation request does not need to send a constantly changing current time and invalidate otherwise cacheable results. It is a deliberate balance of security, performance, and cache behaviour.
The Hybrid Pattern Most Teams Land On
You rarely pick one for the whole app. Use client flags to hide and reveal UI, and pair them with server-side checks for the endpoint or workflow they expose. Use the same flag key and the same user context on both sides so the browser and API are enabled synchronously:
import featureflow from 'featureflow-client';
// Server-side: protect the endpoint with the same key and context.
const client = featureflow.init(process.env.FEATUREFLOW_SERVER_API_KEY!, {
user: {
key: userId, // consistent bucketing per user
attributes: { plan: user.plan },
},
});
// Backend-only decision — never leaves the server.
if (!client.evaluate('redesigned-dashboard').isOn()) {
return res.status(404).end();
}
res.json(await loadRedesignedDashboard(userId));
// Client-side: initialize with the same key and attributes.
// Featureflow returns evaluated values for this user context.
featureflow.init(process.env.FEATUREFLOW_CLIENT_API_KEY!, {
user: {
key: userId,
attributes: { plan: user.plan },
},
});The UI can hide or show the redesigned dashboard without waiting for a deploy, and the backend still refuses requests for users who should not have access. Because both sides use the same key and context, a user bucketed into a variant in the browser is treated the same way by the endpoint.
A Quick Rule of Thumb
If revealing the flag's existence or value would be a problem, keep enforcement server-side. If the flag only changes what the UI looks like and the user could see it anyway, a client flag is a good fit. When a feature spans both, use the same flag key and the same user context in both places so UI and backend access move together.
👉 Featureflow ships both server-side and client-side SDKs with real-time updates, server-side rule evaluation for client flags, smart datetime handling, and CDN-backed delivery so the same flag behaves consistently across UI and backend boundaries. See how it works at featureflow.com or browse the docs.
#FeatureFlags#ContinuousDelivery#DevOps#WebPerformance#Architecture
One flag system, server and client
Start free with Featureflow — consistent targeting and instant kill switches across your whole stack.
Start Now (Free)Related Articles
Feature Flags vs Entitlements: When to Use Which (and When You Need Both)
Feature flags release code safely. Entitlements decide who's paid for what. Collapse them into one toggle system and you'll end up with billing tied to deploys, or risky releases hidden in your pricing layer.
Testing Code That Has Feature Flags: Strategies That Don't Explode Your Test Matrix
Add ten boolean flags and you have 1,024 versions of your app — in theory. Here's how to keep your test suite tractable: stub the SDK, pin variants per test, default to safe, and clean up alongside the flag.
Feature Flags and the Strangler Fig: Refactor Legacy Code Without the Big-Bang Rewrite
Big-bang rewrites kill teams. The strangler fig pattern with feature flags lets you replace legacy code one slice at a time — shadow-testing, ramping traffic, and keeping a kill switch the whole way.