These examples are provider-agnostic. Replace the selectors and paths with the exact shapes used in your codebase.
For Unleash, LaunchDarkly, PostHog, Statsig, and OpenFeature commands, see the feature flag provider guides.
Source:
const enabled = useFlag("new-checkout");
return enabled ? <NewCheckout /> : <CurrentCheckout />
Command:
npx flag-prune --set 'useFlag("new-checkout")=false' --write src
Result:
return <CurrentCheckout />
Source:
if (client.isEnabled("new-checkout", loadContext())) {
startNewCheckout()
} else {
startCurrentCheckout()
}
Command:
npx flag-prune \
--set 'client.isEnabled("new-checkout")=true' \
--write \
src
Result:
loadContext()
startNewCheckout()
The required loadContext() evaluation remains even though its result is no longer needed.
Source:
import { NEW_CHECKOUT as enabled, metadata } from "./flags";
if (enabled) {
startNewCheckout()
} else {
startCurrentCheckout()
}
metadata()
Command:
npx flag-prune --set './flags#NEW_CHECKOUT=false' --write src
Result:
import { metadata } from "./flags"
startCurrentCheckout()
metadata()
If the configured binding is the final import specifier, flag-prune leaves a side-effect import by default:
import "./flags"
Only use --remove-side-effect-imports when the module is proven side-effect-free.
Source:
const variant = getVariant("checkout")
if (variant === "treatment") {
showTreatment()
} else {
showControl()
}
Command:
npx flag-prune \
--set 'getVariant("checkout")=treatment' \
--write \
src
Result:
showTreatment()
Some SDKs return a variant object rather than a bare string. Give the flag its
final object value and flag-prune folds each static member read.
Source:
const variant = getVariant("checkout")
if (variant.enabled && variant.name === "treatment") {
showTreatment()
} else {
showControl()
}
Command:
npx flag-prune \
--set 'getVariant("checkout")={ enabled: true, name: "treatment" }' \
--write \
src
Result:
showTreatment()
If the object is also used as a whole value, the declaration is kept and only the member reads are folded:
const variant = { enabled: true, name: "treatment" }
track(variant)
showTreatment()
A flag inside an object spread often folds to a value that spreads nothing.
Source:
const content = {
state: null,
...(flagValue ? {} : { permission: 1 }),
}
Command:
npx flag-prune --set 'flagValue=true' --write src
Result:
const content = {
state: null,
}
The ...({}) spread is removed because it contributes no properties. See
Empty object spreads are removed
for the exact rules.
Source:
if (limits.maxSeats >= 10) {
showEnterpriseControls()
} else {
showStarterControls()
}
Command:
npx flag-prune --set 'limits.maxSeats=25' --write src
Result:
showEnterpriseControls()
Source:
const theme = readThemeOverride() ?? defaultTheme
Command:
npx flag-prune --set 'readThemeOverride()=null' --write src
Result:
const theme = defaultTheme
npx flag-prune \
--set 'useFlag("new-checkout")=false' \
--set 'getVariant("checkout-copy")=control' \
--set './flags#SHOW_CHECKOUT_BADGE=false' \
--write \
src
Related rules are simplified together, which can remove branches that depend on combinations such as A && B.
npx flag-prune \
--set 'useFlag("new-checkout")=false' \
--diff \
src
Dry-run and diff output are already the defaults, but spelling them out can make a saved migration command easier to understand.
npx flag-prune \
--set 'useFlag("new-checkout")=false' \
--check \
--no-diff \
src
Exit code 1 means files would change. This is useful while a cleanup branch is being prepared or when enforcing a known final value in CI.
npx flag-prune \
--set 'useFlag("new-checkout")=false' \
--json \
src > flag-prune-report.json
The JSON includes an aggregate report and a per-file report.