What to put in the user you pass to a feature flag
Which fields do you pass when you ask whether a flag is on? Most teams answer by handing over the whole user record.
It works on day one. Then a rule needs the plan, so the plan goes in. Then someone wants a beta for one company, so the company goes in. A year later the context holds an email address, a full name and a phone number, and nobody can say which of them any rule reads.
That context travels. You build it in the request handler, but the same user shows up in evaluation events, in the listener you wired to your analytics tool, and in anything you log next to the result. A field you added for convenience is now in each of those places.
Keep it small
Targeting needs an id and the attributes a rule compares against. The id has two jobs: percentage rollouts hash it, so the same id always gets the same variant, and it identifies the user in evaluation events. Use an internal id that means nothing outside your system, not an email.
- Opaque id. A database key or UUID. It stays the same when someone changes their email, so their variant does not change with it.
- Coarse attributes.
plan,country,roles. Pass what a rule actually uses, not every column you have. - Account id for company-wide betas. Target
companyIdinstead of listing every person at the company.
import Featureflow from 'featureflow-node-sdk';
// One place builds the context, so nobody adds fields ad hoc.
export function flagUser(u: AppUser) {
return new Featureflow.UserBuilder(u.id)
.withAttribute('plan', u.plan)
.withAttribute('country', u.country)
.withAttribute('companyId', u.companyId)
.withAttributes('roles', u.roles)
.build();
}
if (featureflow.evaluate('new-reports', flagUser(user)).isOn()) {
// ...
}Rules are evaluated inside your process, so the context does not have to leave your servers for a flag to resolve. That is a reason to be strict about it, because the wider copies come from your own code: the evaluation listener, the log line, the error report.
One builder, one review rule
The function above matters more than the list. When every evaluation builds its user in the same place, adding an attribute is a visible change to a single file, and a reviewer can ask which rule needs it. When each call site assembles its own user, the fields drift and nobody sees it.
If you need to target by something sensitive, such as an email domain for an internal beta, pass the derived value (isStaff: true) and keep the address itself out. Your rule gets the same answer with less data attached.
In Featureflow, the attributes you pass are the ones your targeting rules can use. The docs cover defining a user and targeting by custom attributes.
Today, search your code for the places that build a flag user. Collapse them into one function and delete every field no rule reads.
#FeatureFlags#Privacy#Targeting#ContinuousDelivery#DevOps
Target on the fields that matter
Start free with Featureflow. Target by plan, company or role, and keep an audit trail of every change.
Start Now (Free)Related Articles
Freeze the deploys, not the flags
A change freeze stops merges but not the flag dashboard. Freeze anything that adds risk, keep the switches that remove it, and enforce the rule with approvals.
Don't cache the answer to a feature flag
A cached page remembers the first visitor's flag, and your kill switch waits for the TTL. Evaluate per request and put the variant in the cache key.
Retiring an API version without a surprise outage
A shutdown date hits every client at once, including the cron job nobody owns. Gate v1 with a per-client flag, brown out a slice of traffic, and turn a client back on if they still need the old routes.