Marcio Cunha

Broken deployment? How to implement feature flags with GitOps

Learn how to prevent production failures using feature flags managed through declarative repositories and modern GitOps workflows.

Marcio Cunha•6 min
Also available in:PortuguêsEspañol
Summary
  • Declarative repositories eliminate configuration drift between staging and production environments.
  • Feature flags decouple code deployment from the actual release visible to the end user.
  • GitOps tools synchronize the real infrastructure state directly with code version control.
  • Rollbacks of faulty features become instant through simple commit reversions.
  • Change auditing gains complete traceability with full revision histories in pull requests.

The nightmare of stuck deployments and the promise of GitOps

Anyone who has ever felt the anxiety of pushing new code live and watching the entire system crash knows the pain firsthand. In traditional software engineering, deploying an application to production is often a tense moment filled with uncertainties and emergency rescue meetings. In practice, this means that testing the integrity of an entire system all at once is an open invitation for catastrophic failures affecting thousands of users within seconds. To solve this structural problem, the industry adopted methodologies similar to how to manage Kubernetes secrets with Vault and GitOps, combining continuous automation with rigorous version control.

The big turning point happened when engineering teams realized they could treat infrastructure and configurations in the exact same way they treat their core application source code. This is where the concept of GitOps comes in, which is nothing more than using a centralized Git repository — the most popular version control system on the market — as the single source of truth for everything running on servers. If a configuration is not described and approved in that repository, it simply does not exist in the production environment. This approach eliminates those famous manual tweaks made directly on the server in the dark, which no one remembers making or why.

What are feature flags and why they change the game

Imagine you built a brand new engine for a race car, but instead of swapping the entire engine on the track all at once, you install a dashboard with an on-off switch inside the cockpit. Feature flags — which act as logical switching keys embedded within the code — allow exactly that: deploying new features to production invisibly to the general public. In practice, the new feature's code travels alongside the main application bundle, but it remains dormant and inaccessible until the switch is flipped remotely via a control panel or an external configuration variable.

This absolute separation between deploying code and releasing the feature to the end user completely transforms engineering workflows. When an unexpected bug occurs, instead of spending hours building a new system version and running a tedious rollback process, the team simply toggles the digital switch from on to off in seconds. The system self-corrects instantly without needing to restart servers or rerun complex deployments. Furthermore, this technique pairs exceptionally well with resilience strategies and how to implement observability with OTel to monitor real-time software behavior under pressure.

Centralizing flags in declarative files

Traditionally, managing feature flags relied on closed third-party commercial platforms or chaotic web dashboards where anyone with permissions could alter critical rules without leaving clear audit trails. With the rise of the modern continuous delivery ecosystem, the community began migrating to declarative configuration files — usually written in YAML or JSON formats — saved directly in the project's repository. This means defining who sees a new interface or what percentage of the user base tests a new search algorithm becomes a process controlled by standard code review, requiring approval from peer developers before taking effect.

In practice, the declarative file acts as an immutable contract between developer intent and distributed system behavior. Let us examine a simple example of how this structure looks in everyday configuration files:

flags:  - name: new_payment_checkout    owner: finance-team    status: enabled    rules:      - environment: production        criteria: percentage        value: 20      - environment: staging        criteria: global        value: true

This plain text model brings impressive clarity to the entire organization, allowing product managers, infrastructure engineers, and developers to see exactly which features are active in each environment without guessing hidden rules buried inside legacy databases or inaccessible proprietary panels.

Synchronizing the repository with the cluster using GitOps

Writing declarative configuration files is only the first step of the journey; the true operational challenge lies in ensuring the state described in those files perfectly reflects what is running on live servers. This is precisely where the GitOps cycle shines with maximum intensity, utilizing automated agents installed inside the cluster — such as ArgoCD or Flux — that constantly monitor the Git repository for any configuration updates. As soon as a new commit is approved and merged into the main branch, the agent detects the change and applies the new state in a fully automated and secure manner.

To ensure the workflow runs smoothly without unpleasant surprises, the standard process follows well-defined, auditable steps:

  1. The developer or product manager modifies the flag configuration YAML file in the Git repository and opens a Pull Request.
  2. The team reviews the proposed change, validates the release criteria, and approves the modification through automated tests.
  3. The code is merged into the main branch, triggering the GitOps agent which immediately reads the new declarative state.
  4. The server cluster updates the in-memory flag map, applying the new behavior in a distributed manner without downtime.

This workflow completely removes the human factor when applying infrastructure changes, reducing typing errors in administrative web consoles to absolute zero.

Operational challenges and common pitfalls

Despite all obvious advantages, adopting GitOps-controlled feature flags requires strict discipline to prevent the repository from turning into a graveyard of dead code. The most common problem teams face is the accumulation of stale keys that were never removed from the source code after a feature's final launch. In practice, if a flag was created to test a new button last year and that button is now the absolute default for one hundred percent of users today, keeping that logical check in the code only adds unnecessary complexity and hurts system readability.

Another crucial consideration involves propagation latency when request volumes reach massive scales. If every user request needs to query a heavy static file on disk or make a complex remote call to validate a flag, application performance will plummet rapidly. The solution to this bottleneck is keeping the updated set of flags in an ultra-fast local cache within the application's RAM, allowing the GitOps agent to update only this volatile structure in the background whenever a new commit lands on the official repository. To explore these architectural concepts further in production, see our related technical analysis on Expensive generative AI? How to cut token costs with caching.

Final considerations

The combination of feature flags and declarative GitOps practices represents a genuine evolution in how we handle the risks of pushing software to production. By turning release control into versioned code, companies gain extreme speed without sacrificing operational security and predictability. The secret to success lies in maintaining a culture of continuous code cleanup, ensuring temporary switches fulfill their purpose and are promptly removed once the feature is fully consolidated in the market.

Adopting this mindset means not only using modern automation tools, but fundamentally rethinking delivery culture so that failure is no longer a traumatic event, but merely another quick adjustment point on the engineering control panel.