Feature flags are a powerful technique that can dramatically improve software quality, developer confidence, and even marketing strategies. By allowing developers and product teams to toggle features on and off dynamically, feature flags reduce deployment risks, enable A/B testing, and facilitate gradual rollouts. However, implementing feature flags incorrectly—especially in a React frontend—can introduce performance issues like layout shifts and instability.
In this article, we will explore a server-side feature flag approach in a React.js application that eliminates these problems while enhancing quality and confidence.
Why Feature Flags Should Be Server-Side (Not Frontend)
A common mistake in React applications is implementing feature flags directly in the frontend, such as storing them in local state or using client-side feature flag services. While this may seem convenient, it introduces several challenges:
- Layout Shifts and Jank: If feature flags are fetched asynchronously in the frontend, the UI may render without knowing which features are available, leading to elements appearing or disappearing unexpectedly.
- Flickering Issues: Users might momentarily see disabled features before the flag values load, creating a poor user experience.
- Security Concerns: If feature flags are stored in the frontend, users could inspect them in the browser and manually enable hidden features.
By using a server-side approach, we eliminate these issues by ensuring that the frontend receives the correct flags before rendering the UI.
Implementing Server-Side Feature Flags in React
The best way to manage feature flags is through a backend service that provides them dynamically. Let’s walk through how to do this with a simple Node.js + Express backend and a React frontend.
1. Setting Up the Feature Flag API
First, create a simple backend that serves feature flags to the frontend (you can also use an external library such as Firebase, LaunchDarkly, ConfigCat, etc).
// server.js (Node.js + Express)
const express = require('express');
const app = express();
const PORT = 4000;
// Simulated feature flag storage
const featureFlags = {
newDashboard: true,
experimentalSearch: false
};
app.get('/api/feature-flags', (req, res) => {
res.json(featureFlags);
});
app.listen(PORT, () => console.log(`Feature flag server running on http://localhost:${PORT}`));
2. Creating a Feature Flag Hook in React
Instead of calling the API in multiple components, we create a custom hook to fetch the flags once and store them globally.
// src/hooks/useFeatureFlags.js
import { useState, useEffect } from 'react';
const API_URL = 'http://localhost:4000/api/feature-flags';
export function useFeatureFlags() {
const [flags, setFlags] = useState({});
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchFlags() {
try {
const response = await fetch(API_URL);
const data = await response.json();
setFlags(data);
} catch (error) {
console.error('Error fetching feature flags:', error);
} finally {
setLoading(false);
}
}
fetchFlags();
}, []);
return { flags, loading };
}
3. Using React Context for Global Access
To prevent multiple API calls, we store the flags in a React Context.
// src/context/FeatureFlagContext.js
import { createContext, useContext } from 'react';
import { useFeatureFlags } from '../hooks/useFeatureFlags';
const FeatureFlagContext = createContext();
export function FeatureFlagProvider({ children }) {
const { flags, loading } = useFeatureFlags();
return (
<FeatureFlagContext.Provider value={{ flags, loading }}>
{children}
</FeatureFlagContext.Provider>
);
}
export function useFlags() {
return useContext(FeatureFlagContext);
}
4. Integrating Feature Flags into the Application
Now, we use the feature flags to conditionally render components.
// src/App.js
import React from 'react';
import { FeatureFlagProvider, useFlags } from './context/FeatureFlagContext';
import Dashboard from './components/Dashboard';
import SearchFeature from './components/SearchFeature';
function App() {
return (
<FeatureFlagProvider>
<MainApp />
</FeatureFlagProvider>
);
}
function MainApp() {
const { flags, loading } = useFlags();
if (loading) return <p>Loading...</p>;
return (
<div>
<h1>My Application</h1>
{flags.newDashboard && <Dashboard />}
{flags.experimentalSearch && <SearchFeature />}
</div>
);
}
export default App;
How This Improves Quality, Confidence, and Marketing
✅ Improved Quality & Stability
By enabling gradual rollouts and A/B testing, feature flags reduce the risk of introducing breaking changes into production. Developers can test features in controlled environments before releasing them widely.
✅ Increased Developer Confidence
With feature flags, teams can merge code into production even if a feature is incomplete, knowing that it will remain hidden until fully tested. This allows continuous deployment without fear of releasing half-baked features.
✅ Solving the Hardest Problem in Computer Science: Marketing
One of the biggest challenges in software development is not the code itself but how to market new features effectively. Feature flags allow marketing teams to:
- A/B test features to see what users prefer.
- Release features gradually to gather feedback before a full launch.
- Target specific user segments with experimental features.
Conclusion
Using a server-side feature flag approach in React provides a robust solution for dynamically controlling features without causing UI issues. It enhances software quality, boosts developer confidence, and—most importantly—solves the hardest problem in computer science: marketing.
By adopting this method, teams can deploy features safely, optimize performance, and ensure the best user experience without unnecessary flickering or layout shifts. 🚀
Top comments (2)
I don't think using
launchdarkly-react-client-sdk
is the best approach. Making feature flag decisions on the client side makes your application prone to layout shifts, since the feature flag evaluation happens after the initial render.I recommend reading this article for more information: flags-sdk.dev/knowledge-base/serve...
just considered that, thank you homie 😊