Shipping code is stressful. You have a full test suite of end-to-end tests, linting and manual verification only for something to crash in production.
Here is where feature flags enter the picture. It enables developers to safely deploy ideas in production, roll out features to a particular subset of users and disable it in case anything goes wrong without a redeployment. Let's explore some ways on how to use them effectively:
1. Don't clutter your code by mixing up feature flag logic
//🚫 DON'T: complicated if/elses
function Dashboard({ user }) {
if (flags.enableAnalytics) {
if (user.isAdmin) {
return <AdminAnalytics />;
} else {
return <UserAnalytics />;
}
} else {
if (user.isAdmin) {
return <AdminOverview />;
} else {
return <UserOverview />;
}
}
}
//✅ DO: isolated flag logic
// flagEvaluator.js
export function getDashboardComponent(flags, user) {
const BaseComponent = flags.enableAnalytics ? Analytics : Overview;
return user.isAdmin ? AdminWrapper(BaseComponent) : UserWrapper(BaseComponent);
}
// Dashboard.jsx
import { getDashboardComponent } from "./flagEvaluator";
function Dashboard({ user }) {
const DashboardComponent = getDashboardComponent(flags, user);
return <DashboardComponent />;
}
2. Make ownership clear
Assuming a codebase worked on by a team of multiple people, all feature flags must always have a code owner. This helps massively as they now effectively manage the feature. Having an ambiguous boundary here wastes manpower and resources on who to contact if something goes wrong or for any cleanup.
3. Always test "ON" and "OFF" mode
Generally, when introducing any feature flags, there is more care given to the code paths newly introduced. Always test your "OFF" mode as thoroughly as well - there's always a chance you might need to turn it off due to some issues.
4. Clean up old or redundant flags
All flags, whether shipped or redundant need to be cleaned up - it reduces tech debt and overhead. Ideally, have a system that alerts codeowners of old flags (example criteria - flags not used in say 30 days) and have them take an action against it.
5. Follow naming conventions
A feature flag name does not need to be too descriptive, but it should be able to give any reviewer broader context on what the change does. For example, enable_new_checkout_flow_mobile would be preferred over new_checkout_flow. You can even include a tag descriptive of whether it is an experiment vs permissive flag.
6. Page performance should not be hampered by feature flags
// home-page.js
function HomePage() {
// Multiple async calls for each flag
const showDiscountBanner = fetchFlag("show_discount_banner");
const enableSupportChat = fetchFlag("enable_support_chat");
return (
<>
{showBanner && <Banner />}
{enableChat && <ChatWidget />}
</>
);
}
Notice how in this example, nothing shows up on the home page until at least one of the feature flags are evaluated. My go to solution would be to aggressively cache your flags per user and resolving the flags on the server. Plus, always batch your feature flag calls.
Share your experience
I’d love to hear how feature flags have played out in your projects. Drop a comment with:
Bug stories: Ever had a flag cause chaos in production? How did you fix it?
Top comments (0)