Feature flag management without a dashboard to garden
Feature flag management is the practice of tracking which flags exist, who owns each one, and when it gets removed. Most teams handle it with a dashboard, and a dashboard only works for as long as somebody keeps weeding it. Nobody signs up to be that gardener, so a flag like new-checkout-v2 sits at 100% for three years with a dead branch behind it, and nobody remembers why. This post covers managing feature flags without a dashboard: as files in the repo, reviewed in a pull request, and checked in CI instead of by a human remembering to log in.
Key Takeaways
- Feature flag management is three jobs: knowing what’s live, who owns it, and when it comes out. A dashboard handles the first job and leaves the other two to memory.
- In dif, each flag is one Markdown file with an
ownerfield the validator enforces, so a flag with no name on it fails CI instead of a code review nobody did.dif validatescans your app source fordif("...")call sites and fails the build on an orphaned reference, catching what a human reviewer would miss.- The lifecycle is a four-step loop:
dif new,dif validate,dif build,dif conclude. There’s no fifth, undocumented state for a flag to drift into.- Rollback is a commit, not a toggle. For a payment path that needs a sub-second kill switch, that’s a real cost, not a tradeoff to paper over.
What feature flag management actually covers
Feature flag management covers three separate jobs, and most tooling only does the first one well.
The first job is visibility: what flags exist right now, and what do they gate. The second is ownership: who is responsible for each one, and can you reach them. The third is removal: when does this flag come out, and who notices if it doesn’t.
A dashboard answers the first question. It lists flags, because listing rows is what a database is for. It does not answer the second or third, because ownership and a removal date are facts about intent, and a dashboard has no field that enforces either one. Most let you type an owner into a free-text description, which is the same as not asking.
The dashboard needs someone to garden it
A list of flags is only as good as the person pruning it, and gardening a dashboard is nobody’s job description.
The common failure looks the same everywhere: a flag like new-checkout-v2 goes to 100%, the team moves to the next sprint, and the dead branch behind the flag stays in the codebase because deleting it means someone first has to confirm the flag is really done. That confirmation step lives in a dashboard nobody opens unless something breaks. A new hire finds the flag two years later, has no way to tell if it’s safe to remove, and leaves it alone. The flag outlives the reason it existed.
The stakes are not always this mild. In 2012, Knight Capital Group lost $460 million in 45 minutes when a repurposed flag on one of eight trading servers re-enabled old, dormant code nobody had removed. The SEC’s order describes exactly this pattern: a flag reused without first confirming what it still triggered. Most flag debt is not a trading incident. It is the same unmanaged pattern at a smaller scale.
Manage feature flags as files in git
The fix is not better dashboard discipline. It’s moving the source of truth into the place where ownership and review already happen: the repo.
In dif, a flag is one Markdown file, structured frontmatter on top, prose below:
---
id: new-checkout
owner: priya@example.com
status: active
variants:
- name: off
weight: 9000
- name: on
weight: 1000
---
The owner field is not a convention. dif validate checks that it looks like a real email and fails the pull request if it’s missing. The flag gets reviewed the way every other change to the repo gets reviewed: in a PR, by a person who reads the diff. The .md format covers the rest of the frontmatter, including audiences and exclusion groups. Removing a flag is a commit too, so the history of why it existed is the git history, not a Slack thread from two years ago.
This is also how dif stays usable straight from git, not a dashboard: flags get reviewed the same way the code they gate does.
dif validate catches what a dashboard misses
A dashboard shows you flags. It doesn’t check them against your code, because it has never read your code.
dif validate does, in one pass:
$ dif validate
✓ 14 flags checked, weights sum to 100
✓ 14 owners valid
✗ new-checkout: no call site found in src/ (orphaned)
✗ pricing-page-v2 and pricing-copy-test collide on surface "pricing" (E007)
2 errors, 0 warnings
A dashboard can’t do either of these two checks. First, orphan detection: the validator scans your app source for dif("...") call sites and flags a file with no matching reference, the opposite direction of the usual failure (code referencing a flag that doesn’t exist). Second, collision detection: two active experiments targeting the same surface fail the build (error E007) unless they share an exclusion group or have provably disjoint audiences, so you never ship a test you can’t attribute. The CLI reference covers every check it runs.
A broken flag fails the PR the same way a broken test does, so nobody has to remember to check.
The lifecycle loop: new, validate, build, conclude
A dashboard has no lifecycle. A flag goes in, and it sits there until a person remembers to take it out. dif’s loop has four steps, and each one is a command:
dif newscaffolds a draft, pre-loaded with the last three learnings from that surface, so nobody re-runs a test the team already answered.dif validatechecks weights, owners, and references before anything ships.dif buildcompiles active flags into a typed client andcontext.json, so the flag goes live and a coding agent can read it in the same step.dif concludedates the decision, writes a one-line learning back to the surface, and archives the file.
A flag that’s done gets concluded, not abandoned mid-rollout with a dashboard row still sitting there. ls dif/*/active/ is the whole list of what’s in flight, no login required.
The cost of git-native flag management
Git-native flag management is slower to roll back, and that’s worth stating plainly.
Turning a flag off means editing a number to 0 and merging, so a build and a deploy stand between you and off. If your build takes 10 minutes, your worst-case kill is 10 minutes. For an ops flag gating a payment path that needs a sub-second kill switch, that’s the wrong tool, and a platform built around an instant toggle is the right one for that specific flag.
For most flags, where the failure mode is “some users see the new thing a little longer than planned,” a merge and a deploy is fine. The tradeoff buys you something a toggle never gives you: the reason for the rollback is in the commit message, not in someone’s memory of a 2 a.m. page.
FAQ
What is feature flag management? Feature flag management is tracking which flags exist, who owns each one, and when it gets removed, not just turning a feature on or off. A tool that only lists flags is solving the easiest third of the problem.
Do you need a dashboard to manage feature flags? No. A dashboard is one way to list flags, but ownership and removal are the harder jobs, and a file reviewed in a pull request with a validator enforcing the owner field handles both better than a free-text field in a UI.
How do you stop feature flags from piling up? Enforce an owner on every flag, run a check in CI that fails on an orphaned reference, and give flags a conclude step instead of letting them idle at 100%. dif validate and dif conclude do exactly those jobs.
What’s the difference between feature flag management and feature flagging? Feature flagging is the mechanism: wrapping a code path in a condition you can flip, what Martin Fowler’s canonical feature toggles article covers in depth. Feature flag management is the process around it: ownership, review, staleness checks, and a removal path, which is the part most tooling skips.
Does feature flag management work without an account? Yes, in dif. npm install -g @dif.sh/cli, then dif init scaffolds the workspace. There’s no signup and no dashboard to log into for the CLI and SDK to work.
Managing flags without a dashboard
Feature flag management is three jobs, not one: know what’s live, know who owns it, know when it comes out. A dashboard handles the first job and leaves the other two to whoever remembers. Putting flags in the repo as files puts all three jobs where ownership and review already happen.
dif validate enforces the owner field and catches orphaned references in CI. The lifecycle loop, new, validate, build, conclude, gives every flag an exit instead of a quiet rot at 100%. The tradeoff is real: rollback is a commit, not a toggle, so a sub-second kill switch belongs to a different tool for that one flag.
Install the CLI and try it on one flag: npm install -g @dif.sh/cli, then dif init. The feature flags page covers the full file-based model, and the docs have the rest.