GitOps for Feature Flags: How the Workflow Actually Runs

Run feature flag config through git: where it lives, what a reviewer checks, how CI applies it, and why some configuration drift is correct and should stay.

  • gitops
  • automation
  • best-practices

GitOps for feature flags means the flag configuration that outlives any single release lives in a git repository, changes through pull requests, and reaches the platform through CI. Which flags exist, what variations they carry, which segments they target, what the targeting rules say. All of it declared, diffed, reviewed, and applied by a machine. The practice is flags as code, and this is the workflow around it.

There is one wrinkle, and it is the reason this workflow needs its own treatment rather than a copy of the one you already run for infrastructure. Feature flags are the single piece of production you deliberately change outside the pipeline. A kill switch that waits on a plan and an apply is a kill switch that failed. So the interesting question is where the declared path stops and the fast path begins, and what happens to the gap between them.

Key Takeaways

  • Declare the structure, which is flags, variations, segments, and stable targeting. Leave incident-time toggling on the fast path.
  • The highest-blast-radius line in a flag diff is usually the fallthrough variation, and it looks like nothing.
  • Rule order carries meaning. A diff that only moves a block changes who gets what.
  • Some drift is correct. A flag flipped at 3am is drift, and reverting it automatically would be the bug.
  • Run plan on the pull request with a read-only token, and apply on merge with a scoped write token.

1. What GitOps means when the thing you declare is a flag

GitOps is a narrow idea with a big name. Desired state lives in a repository, something reads it, and that something makes reality match. Most people met the pattern through Kubernetes, but nothing in it is specific to clusters.

The part that transfers cleanly to flags is the structural configuration. A flag’s existence, its type, its variations, the segments it targets, and the shape of its rollout rules are all long-lived and they accumulate. Six months in, nobody remembers why the flag that gates checkout targets three overlapping segments, and no dashboard will tell you. A repository will.

The part that does not transfer is the reconciliation loop. Infrastructure tooling assumes any difference between declared and actual state is a defect, so it corrects on a schedule. Flags break that assumption on purpose. Section 5 covers what to do about it, because getting this wrong is the most expensive mistake in the whole workflow.

Flag configuration is the whole scope here. Reading a value for a user at runtime stays in your application through an SDK, in memory, on the request path, and nothing described below touches it.

2. Where the configuration lives

Two layouts work, and the choice is about who reviews changes rather than about tooling.

Co-located with the service. Flag declarations sit in the same repository as the code that reads them, usually beside whatever infrastructure that service already declares. Reviewers are the people who own the feature, so they know what the flag is for. This is the right default while your flag count is small and each flag belongs to one team.

A dedicated flags repository. All declarations in one place, reviewed by whoever owns release process. This starts to pay off once several teams share segments, or once someone needs to answer “what is enabled in production right now” without cloning six repositories.

Either way, the tool writes state, and that state holds secrets. SDK keys in particular are readable in plaintext once they land there, so the state backend needs the same treatment as any other secret store. The Terraform provider guide covers the specifics of that, along with the resource types and the import path for flags you already created by hand.

3. What a reviewer is actually looking at

This is where a flag pull request stops resembling an application pull request, and it is the part most teams learn by getting it wrong once.

Start with the fallthrough. One line, reads like a default, decides what happens to every user who matches no rule:

resource "featureflip_flag_environment" "checkout_prod" {
environment = "production"
enabled = true
default_variation = "false"
default_variation = "true"
}

That diff turns the feature on for everyone the targeting rules did not already catch, which is a full release expressed as a one-word change, sitting under two lines that did not change, in a file where the eye is drawn to the rules block below it. Reviewers who scan for large diffs miss it every time.

Then check rule order. Rules evaluate top to bottom and the first match wins, so list position is priority, and a diff that moves a block without editing a character of it still changes who gets what. Git renders that as a delete and an insert somewhere else in the file, so it reads as churn when what actually changed was the targeting.

After that, three quicker passes:

None of this requires the reviewer to be the person who wrote the feature. It does require a review checklist, because the failure mode here is a diff that approves itself on the strength of being small.

4. Plan on the pull request, apply on merge

The pipeline is two jobs and one asymmetry between them.

On pull request, run the plan and post its output as a comment. The HCL diff shows intent and the plan shows consequence, including every resource the change touches that nobody thought about, so the plan is what the reviewer should be reading. For flag work those two diverge more often than they do for infrastructure, because a single segment edit fans out.

On merge to your default branch, apply. Authenticate with a service token scoped to one organization, with a project allowlist, rather than a personal token that carries whatever access its owner happens to have. The Management API authentication docs cover the token types.

Give the plan job a read-only token and the apply job a write token. Plan runs against pull requests, which means it runs against code from forks and from anyone who can open one. Read-only there costs nothing and closes the obvious hole.

Every change now also carries a commit message, an author, a review, and a history with no retention limit. Featureflip records every flag change automatically with actor and before-and-after values, and that log is the right tool during an incident, but it ages out at 7 days on the free plan. Git keeps the structural history for as long as the repository exists.

5. Drift, and why some of it is correct

Both paths write to the same platform, at very different speeds.

The reviewed path and the fast path into a feature flag platform Two paths reach the same flag platform. The reviewed path runs from the repository through a pull request with a plan, then a merge, then a CI apply. The fast path runs directly from an incident to the dashboard or API, bypassing review, and reaches the platform in seconds. The difference the fast path creates is folded back into the repository afterwards as a pull request. The reviewed path minutes to hours, and that is fine Repository declared state Pull request plan + review Merge CI applies Flag platform actual state The fast path seconds, and that is the whole point Incident 3am, one person Dashboard flag off, now afterwards: fold the change back in as a pull request
Both paths write to the same platform. The gap they open is drift, and closing it is a human decision.

Drift is any difference between what the repository declares and what the platform is actually serving. In infrastructure that difference is a defect. Here it is often the system working exactly as designed, because someone used the kill switch at 3am and saved the evening.

Two rules cover it.

Declare only what you are willing to have reverted. Anything under the tool’s control goes back to the declared value on the next apply, without ceremony. That is the correct behaviour for a segment definition and the wrong behaviour for the on/off state of a flag your team ramps daily. Most teams land on managing existence, variations, and segments everywhere, then managing rules only for the flags whose targeting is genuinely stable.

Reconcile on a decision, not on a timer. Scheduled auto-apply is a normal, sensible pattern for infrastructure and a foot-gun here, because it will silently re-enable a feature somebody turned off for a reason at some point when nobody is watching. Apply on merge. A human is always in the loop, which is the property you want.

Real drift then has an obvious home, and it makes the paperwork do double duty. After the incident, open a pull request that brings the repository in line with what the dashboard now says. The diff records what changed, the description carries the reason, and the review is where somebody finally asks whether it should stay that way. One artifact, and you have both the reconciliation and the incident write-up.

6. Promoting a change through environments

Environments are separate resources, so a change reaches staging and production as separate declarations. That is verbose, and the verbosity is doing real work, since the whole reason environments exist is that they hold different values.

The failure here is copy-paste. Someone gets targeting right in staging, copies the block, changes the environment string, and ships a production rule referencing a segment that only exists in staging, or a percentage that made sense against staging traffic. Copy the structure deliberately and re-derive the numbers.

Promotion itself is a normal pull request. The reviewer’s job is the section 3 checklist with more attention, because the environment string is the only thing separating the two.

7. What this costs

Being straight about the trade, since the tooling pages rarely are.

Every structural change is now slower. That is the point, and it is still a cost, and it lands hardest on the person who wanted one flag for one afternoon’s experiment. Give people an escape hatch for genuinely temporary flags or they will route around the whole thing.

Your state file is now a secret, with real consequences if it leaks. Your team needs to know that rules are authoritative once declared, or somebody’s dashboard edit vanishes on a Tuesday and trust in the pipeline goes with it. And below a handful of flags managed by one team, the honest answer is that this is overhead with no return. The workflow starts paying when nobody can hold the flag inventory in their head, which is also roughly when flag cleanup stops happening by itself.

The pattern still earns its place. Adopt it in the order the value arrives, starting with flag existence and segments, adding targeting once your rules stop moving weekly, and leaving toggling out of it permanently.


The shorter version

GitOps for feature flags puts the structural configuration into a repository and applies it through CI, so flag changes get the review, history, and reproducibility that the rest of your infrastructure already has. Declare flags, variations, segments, and stable targeting. Review the fallthrough line first, then rule order, then which environment the diff touches. Plan on the pull request with a read-only token, apply on merge with a scoped write token. Leave incident-time toggling on the fast path, treat the drift it creates as correct, and fold it back into the repository afterwards as a pull request that doubles as the incident record. Adopt it when the flag inventory outgrows anybody’s memory, rather than on day one.


Frequently asked questions

What is GitOps for feature flags?

GitOps for feature flags is managing flag configuration as declared state in a git repository, reviewed through pull requests and applied to the flag platform by CI. The declared state covers structure: which flags exist, their variations, the segments they target, and their targeting rules. It deliberately excludes runtime evaluation, which stays in your application through an SDK, and usually excludes day-to-day toggling, which needs to be faster than a pipeline allows.

Should feature flag targeting rules live in git?

For flags whose targeting is stable, yes, because a rule change is a production behaviour change and it benefits from a diff and a reviewer. For flags your team iterates on daily, leave the rules out and manage only the flag’s existence and variations. Declared rules are authoritative, and that is what decides it. Once a tool manages them, a rule added in the dashboard is removed on the next apply, which is correct for stable targeting and disruptive for a flag somebody is actively tuning.

How do you handle a flag that was toggled during an incident?

Leave it. The toggle was the right call and reverting it automatically would undo an incident response. Afterwards, open a pull request that updates the repository to match the platform, with the reason in the description. That closes the drift, creates a reviewable moment to decide whether the change should stay, and leaves a permanent record of what happened. Avoid scheduled auto-apply on flag configuration, since it turns this from a decision into a surprise.

Do you need Terraform to manage feature flags as code?

No. Any tool that can drive the platform’s REST API works, including a script in CI that reads a YAML file and calls the Management API. Terraform is the common choice because it brings state, drift detection, and a plan step for free, and because most teams already run it. The requirement is that configuration lives in version control and reaches the platform through review. Which tool performs the last step is secondary.

Does managing flags in git slow down releases?

It slows down flag configuration changes. Releases are unaffected. Creating a flag or editing a segment now takes a pull request. Releasing behind a flag that already exists is unaffected, and turning a flag off during an incident is unaffected, because both stay on the fast path. Teams that report the workflow slowing them down have usually put toggling under version control too, which is the one thing to keep out of it.


Featureflip is a flat-priced feature flag platform, and flags-as-code is on every plan rather than reserved for an enterprise tier. The Terraform provider and the public Management API both work on the free tier, alongside the MCP server if you would rather drive flags from your editor. See the step-by-step Terraform guide for the resource reference and the import path, or start on the free Solo plan without a credit card.