Rollout & Scheduling
Two ways for a flag's value to be decided automatically — by population percentage, or by date — rather than by a manual override.
Percentage rollout
Instead of a plain boolean or string, a flag in the flags option can be a { value, rollout } object:
app.use(FeatureToggles, {
flags: {
newSearch: { value: true, rollout: 0.2 }, // 20% of users
},
userId: currentUser.id, // stable per-user identifier
})rollout is a number between 0 and 1. Each user is bucketed deterministically: the flag name and userId (falling back to 'anonymous' if userId isn't set) are hashed together, and the user gets value if the hash falls under the rollout threshold — otherwise the flag resolves to false, never to defaultValue. The same userId always lands in the same bucket, so a rollout never flickers for a given user across reloads, and increasing the percentage later only ever adds users to the enabled group, it never removes any.
const { getRollout } = useFeatureProvider()
getRollout('newSearch') // → 0.2Rollout resolution happens once, when the provider is created — changing userId later does not re-bucket existing flags reactively.
Scheduling
A flag can be forced off outside a configured date window, independent of any manual override:
app.use(FeatureToggles, {
flags: { holidayBanner: true },
schedule: {
holidayBanner: { from: '2025-12-01', to: '2025-12-31' },
},
})interface FlagSchedule {
from?: string // ISO date — flag is forced off before this date
to?: string // ISO date — flag is forced off after this date
}Both from and to are optional — omit from for an "active until" window, or to for an "active from" window. The check re-evaluates every minute while the page is open, so a scheduled flag flips on/off live without a reload.
Scheduling only forces a flag to false when it's otherwise resolved to something else — it never overrides an active URL override or a runtime setFlag() call, so a manual override always wins over an inactive schedule window. See the full priority order for exactly where scheduling sits relative to the rest of the chain.
const { getSchedule, isScheduleActive } = useFeatureProvider()
getSchedule('holidayBanner') // → { from: '2025-12-01', to: '2025-12-31' }
isScheduleActive('holidayBanner') // → true only inside the window (or if no schedule is set)getFlagSource('holidayBanner') returns 'schedule' while an inactive window is the reason the flag reads false.