Long-lived feature branches are a bad default — they accumulate conflicts, drift from main, and are painful to review.
Better: merge incomplete features into main behind a feature flag.
if (flags.isEnabled('new_search', user)) {
return newSearch();
}
return legacySearch();
Workflow:
- Day 1: PR adds the flag (default off) + new code path. Lands on main.
- Day 2-N: PRs land more pieces. Flag stays off.
- Day N+1: Flip the flag to 10% rollout. Watch metrics.
- Day N+5: 100% rollout. Remove flag + legacy code.
Benefits:
- No branch drift; everyone integrates daily.
- Decouple deploy from release — a deploy makes the code live, the flag flip makes the feature visible.
- Easy kill switch if production goes sideways.
Tools: LaunchDarkly, ConfigCat, GrowthBook, Unleash, or a simple feature_flags table in Postgres.