Ship Features Without the Fear: A Guide to Feature Flags
Learn how to use feature flags to safely roll out new features to a percentage of your users, run A/B tests, and instantly disable problematic code without deploying.
There’s a moment every developer knows too well. You’ve been working on a new feature for weeks, maybe months. The code is tested, the PR is approved, and you’re ready to deploy. But there’s this knot in your stomach because you know that no matter how much testing you’ve done, production is a different beast. Real users do unexpected things. Edge cases you never imagined suddenly appear. And if something goes wrong, your only option is to roll back the entire deployment and figure out what happened.
We built feature flags into Loggy because we got tired of that feeling. The idea is simple but powerful: instead of deploying code that’s immediately active for everyone, you deploy code that’s hidden behind a flag. Then you control who sees it, when they see it, and you can turn it off instantly if something goes wrong. No deployment required.
The Two Types of Feature Flags
When you create a feature flag in Loggy, you choose between two types, and understanding the difference is key to using them effectively.
The first type is a simple toggle - it’s either on or off for everyone. This is perfect for things like maintenance mode, kill switches for problematic features, or enabling beta functionality for your entire user base at once. You flip the switch, and the change takes effect immediately across all your users.
The second type is percentage-based, and this is where things get interesting. Instead of all-or-nothing, you can say “I want 10% of users to see this new feature.” Loggy will consistently route the same users to the same experience, so user Alice will always see the new feature while user Bob will always see the old one. This consistency is crucial because you don’t want users randomly flipping between experiences every time they refresh the page.
How Percentage Rollouts Actually Work
Let me explain the magic behind percentage-based flags because it’s not as complicated as it might sound, and understanding it will help you use them more effectively.
When you call our API to check a flag, you pass two things: the flag key and an identifier. The identifier is typically your user’s ID, but it could be a session ID or any unique string that represents who you’re checking the flag for. Here’s what a typical call looks like:
curl "https://loggy.dev/api/feature-flags/evaluate/YOUR_ACCOUNT_ID/new_checkout?identifier=user_123"
Behind the scenes, we take that flag key and identifier, combine them, and run them through a hash function. This produces a number between 1 and 100. If that number is less than or equal to your percentage setting, the flag is enabled for that user. If it’s higher, the flag is disabled.
The beautiful thing about hash functions is that they’re deterministic - the same input always produces the same output. So new_checkout plus user_123 will always produce the same hash, which means user_123 will always get the same result. But user_456 will produce a different hash, potentially putting them in a different bucket. Over a large enough user base, you’ll get pretty close to your target percentage.
One quick note on that curl command: if you’re using zsh (the default shell on modern Macs), you need to wrap the URL in quotes because the ? character has special meaning to the shell. Without quotes, you’ll get a confusing “no matches found” error that has nothing to do with the API.
A Practical Example: Rolling Out a New Checkout Flow
Let’s walk through a real scenario. Say you’ve rebuilt your checkout flow and you want to test it with real users before going all-in. Here’s how you’d approach it with feature flags.
First, create a flag in Loggy called something like “New Checkout Flow” with the key new_checkout_v2. Set it to percentage-based and start with something conservative, like 5%. This means roughly 1 in 20 users will see the new checkout.
In your code, you’d check the flag before deciding which checkout to show:
async function getCheckoutVersion(userId) {
const response = await fetch(
`https://loggy.dev/api/feature-flags/evaluate/${LOGGY_ACCOUNT_ID}/new_checkout_v2?identifier=${userId}`
);
const { enabled } = await response.json();
return enabled ? 'v2' : 'v1';
}
// Then in your checkout route
const version = await getCheckoutVersion(currentUser.id);
if (version === 'v2') {
renderNewCheckout();
} else {
renderOldCheckout();
}
Now you deploy this code and watch. Check your conversion rates, look for errors in your logs, monitor your support tickets. If everything looks good after a day or two, bump the percentage to 25%. Then 50%. Then 100%. At any point, if you see problems, you can drop it back down or turn it off entirely - no deployment needed.
The Identifier Matters More Than You Think
I want to spend a moment on the identifier because getting it right is important for a good user experience. The identifier determines which bucket a user falls into, so you need to think about what kind of consistency you want.
If you use the user’s account ID, they’ll get a consistent experience across all their devices and sessions. Log in on your phone, log in on your laptop, you’ll see the same version of the feature. This is usually what you want for features that affect the user’s workflow or data.
If you use a session ID instead, the same user might see different versions in different sessions. This can be useful for certain types of A/B tests where you want to measure how the same user responds to different experiences over time, but it can also be confusing if the feature is something visible like a UI change.
You can even get creative with identifiers. Want to roll out a feature to 50% of your paying customers but 0% of free users? Use an identifier like paid_${userId} for paid users and don’t check the flag at all for free users. The hash will distribute your paid users evenly while keeping free users on the old experience.
When Things Go Wrong
Here’s the scenario that makes feature flags worth their weight in gold. It’s 2 AM, you’re asleep, and your new checkout flow has a bug that’s causing payments to fail for the 25% of users who are seeing it. Without feature flags, someone needs to wake up, figure out what’s wrong, prepare a fix, deploy it, and hope nothing else breaks in the process.
With feature flags, whoever’s on call can simply log into Loggy, find the flag, and turn it off. The new checkout disappears instantly, all users go back to the old flow, and the payments start working again. The fix can wait until morning when everyone’s awake and thinking clearly.
This is why we recommend having feature flags around any significant new functionality, especially anything that touches money, user data, or core workflows. The few minutes it takes to wrap code in a flag check can save hours of stressful middle-of-the-night debugging.
Getting Started
Feature flags are available on all Loggy plans. Free accounts get 5 flags with simple on/off toggles. Pro and Team accounts get percentage-based rollouts, which is where the real power lies for gradual releases and A/B testing.
To create your first flag, head to the Feature Flags page in your dashboard. Give it a descriptive name, choose your type, and you’ll get the API endpoint you need to check it from your code. The API requires no authentication for reads, so you can call it from anywhere - your backend, your frontend, even a shell script.
The goal is to make shipping less scary. Deploy your code, control who sees it, and sleep better at night knowing you can turn it off if you need to. That’s what feature flags are all about.