GitOps promised a better way to run infrastructure. Put everything in Git. Use pull requests instead of tickets. Let automation handle deployments. In theory, it’s clean, auditable, and safe.
In practice, many GitOps implementations end up recreating the same operational bottlenecks they were meant to eliminate, just with YAML and CI pipelines instead of runbooks and change tickets.
If GitOps feels complicated, fragile, or overly procedural in your organisation, that’s not because GitOps “failed.” It’s because most teams stopped halfway through the idea.
In this article, I’ll walk through a GitOps model that’s a bit different from what you usually see. It leans hard on declarative configuration, treats intent as data in Git, and lets reconciliation, not pipelines, decide what actually runs in production. In this article, Configuration as Data (CAD) and Config Sync (it will work the same with Flux or ArgoCD) set the stage for a simpler and more predictable way to run platforms.

GitOps, at Its Core
At its heart, GitOps is still operations done the developer way.
Instead of filing tickets or manually touching systems, engineers make changes in Git repositories. Those changes go through pull requests, automated validation, and controlled promotion across environments. Git is the source of truth, and automation ensures reality matches what’s declared.
The familiar pillars still apply:
- Infrastructure as Code (IaC)
Infrastructure and platform configuration are defined declaratively and stored in Git. The small difference for us, though, is that there will be a much greater emphasis on declarative “config”, rather than imperative “code”. - Pull Requests act as the “Interface for Change Control”
Every change goes through review, testing, and approval. - Automation and Reconciliation
Systems continuously converge toward the desired state defined in Git through constant end-to-end reconciliation. - Idempotency
Applying the same configuration repeatedly always yields the same result.
So what changes in a modern GitOps model isn’t what GitOps is, it’s how we apply it.
The Problem with “Traditional” GitOps at Scale

Many GitOps implementations quietly drift back toward imperative thinking:
- Pipelines decide what to deploy and where
- Promotion logic is encoded in CI scripts instead of configuration
- Environment differences are scattered across branches and repository variables, often unavailable to view by engineers.
- Operators and platform components are promoted implicitly, not explicitly
This works… until it doesn’t.
At scale, teams want:
- Clear, auditable intent
- Minimal pipeline logic
- Strong separation between configuration and execution
- A single, declarative view of “what should be running, where, and why”
That’s where Configuration-as-Data comes in.
Configuration-as-Data (CAD)
Configuration-as-Data treats configuration not as templated text, but as structured, versioned data that describes intent.
Instead of asking pipelines to “deploy version X to environment Y,” we declare:
Environment Y should run version X of this component.
…Everything else is reconciliation.
Key ideas behind CAD:
- Configuration is authoritative data, not a side effect of pipelines
- Environments consume configuration by reference, not by copy or computed results.
- Promotion is an explicit data change, not an implicit pipeline step
- Systems continuously reconcile desired state from Git
This approach dramatically simplifies GitOps workflows, and that’s where tools like Config Sync, Flux and ArgoCD shine.
Introducing Config Sync
Config Sync is a GitOps reconciler that continuously applies configuration from Git to Kubernetes clusters. Rather than relying on CI/CD pipelines to push changes, clusters pull their desired state directly from Git.
Some of the key properties of Config Sync are:
- Git becomes the single source of truth for declared config, rather than being an input into functions in a pipeline.
- Config Sync clusters continuously reconcile against this declared configuration, rather than pipelines being configured to run every N hours
- Changes are applied declaratively, not imperatively. WYSIWYG.
- Drift is detected and corrected automatically by Config Sync; there is no need to write any special implementation to do this.
Most importantly, Config Sync enables a clean separation between:
- What is declared (configuration-as-data)
- How it is enforced (continuous reconciliation)
A Modern GitOps Workflow with CAD and Config Sync
Let’s walk through a concrete example of how this works in practice. Below is the process of how our developers at Mesoform go from nothing to deploying a Kubernetes operator.
Understanding Kubernetes Operators
First off, what is an operator? At its core, a Kubernetes Operator is a method of packaging and managing applications by extending the Kubernetes API. Think of it as a digital Site Reliability Engineer — it codifies human operational knowledge to automate complex, stateful tasks like backups and upgrades. This allows us to manage sophisticated software with the same consistency and automation as a simple container, ensuring our infrastructure remains self-healing and scalable.
Our Promotion-Based Release Strategy
To deploy these safely, we follow a “build once, promote many” pipeline that ensures environmental parity. Every image starts with a Git commit tag, progressing through Sandbox, Integration, and UAT registries as it passes automated validation.
For the final move to production, we re-tag the proven commit with a formal version number before pushing to our Live environment. We separate the “production” stage into 2 environments, “staging” and “live”and we tag an image with something like v0.2.1 for it to be used on staging; then, once that has been confirmed all okay, we add a v0.2.4-stable tag on the same image/commit and that is deployed to live).
This rigorous process — managed via a Config Sync RootSync controller for automated reconciliation — ensures that the version running in production is identical to the one verified by our developers, providing a reliable and auditable path to every release.
1. Configuration as the Product
Instead of embedding environment logic in pipelines, we define it in Git:
- Platform configuration repositories describing clusters, organisational (business) units, and compliance policies
- An operators repository for code (following software engineering best practices) for our operators. Everything for the Operator is defined here, including the configuration needed for image builds and the cluster manifests for when the operator is deployed to a cluster.
- Environment configuration explicitly references operator versions by tag
2. Development and Sandbox Experimentation
We define 2 stages and many environments for our software development lifecycle (SDLC). We have a development stage, which consists of sandbox, integration (testing) and acceptance (testing) environments; and production, which has staging and live, as covered before. A common workflow of an engineer would be as follows:
Create a feature branch and make a change:
- Adjusting memory limits configuration
- Modifying a process of the operator’s codified workflow
- Update the operators’s version
A pull request triggers:
- Schema checks
- Policy validation
- Runs unit tests
Config Sync applies the change to a sandbox cluster automatically from the engineer’s feature branch, giving fast feedback without risk.
3. Pull Requests as Promotion Gates
Promotion between environments is handled by changing data, not pipelines.

- Merging into develop updates integration clusters so that the updated operator can be seen working alongside all other operators scheduled to go to production and make some rudimentary calls to external systems which wouldn’t work, or be allowed in sandbox.
- Merging into main will push to our acceptance cluster where actual management of “safe” resources are implemented. This gives us a final “eat your own dog food” acceptance of everything working together doing the things that is expected. You could think of this as a Private Alpha.
- This is the end of our development stage and now we’re ready to move to the production stage. This is done using tags like vN.N.N and vN.N.N-stable where each represents an explicit approval step. The first releases to our production staging environment and the second releases to our production live environment. They are both a replica of each other, even down to access controls. Customers get to use the staging version for earlier environments in their own SDLC to have confidence in changes before production.
Each promotion is:
- A small, reviewable diff — in the case of staging -> live, there is no difference, the same commit ref and thereby all the same image versions and code are the same.
- Fully auditable — every change has a complete history recorded in git
- Easy to roll back — unless there is a need to roll-forward for data integrity, rolling back is simply updating the environments to use the version prior to the current one. E.g. v2.1.1 back to v2.1.0
No hidden logic. No magic.
4. Continuous Reconciliation
Once merged, Config Sync ensures clusters continuously match Git:
- If a cluster drifts, it is corrected
- If a change is reverted in Git, the cluster follows
- If a new cluster is added, it converges automatically
Operations becomes a matter of maintaining the correct configuration, not executing deployments.

Operators, Revisited
Operators also follow a similar lifecycle with the added addition of code-related builds and testing (e.g. unit tests). This will be familiar to normal normal app SDLC: build, test, release, but with clearer boundaries.
- Very small and simple pipelines in the operators repository tests, builds and delivers immutable, environment-agnostic images.
- The platform configuration decides which versions of these images to deploy; and where and when they’re deployed
- No operator is promoted unless the configuration explicitly references it
This guarantees that production runs only what was intentionally approved, and nothing else.
Why This Approach Works Better
This modern GitOps model delivers tangible benefits:
For Engineers
- Zero pipeline complexity
- Faster, safer experimentation
- Clear ownership and intent
- Easier rollbacks and debugging
For Platform Teams
- Strong separation of concerns
- Declarative, auditable promotion
- No imperative logic outside of the scope of the operators themselves
- Easier multi-cluster management
For Leadership and Governance
- Clear approval boundaries
- Complete audit trails
- Predictable, repeatable change management
- Reduced operational risk

GitOps becomes less about “how we deploy” and more about how we declare intent.
Conclusion
GitOps isn’t just about using Git. It’s about trusting declarative systems to do the right thing.
By embracing Configuration-as-Data and tools like Config Sync, teams can move beyond pipeline-heavy GitOps and toward a cleaner, more scalable model:
Declare intent → Review changes → Merge → Reconcile continuously
No tickets. No guesswork. No surprises. It’s a mindset change:
Make configuration the product, Git the contract, and reconciliation the engine that keeps everything honest.
Curious about applying this approach in your own platform?
I’m always happy to compare workflows, share lessons learned, or help teams move toward a more declarative, scalable GitOps model.
Originally published at https://www.mesoform.com
GitOps, Reimagined: A Declarative, Configuration-as-Data Approach was originally published in Google Cloud – Community on Medium, where people are continuing the conversation by highlighting and responding to this story.
Source Credit: https://medium.com/google-cloud/gitops-reimagined-a-declarative-configuration-as-data-approach-b83349e7762a?source=rss—-e52cf94d98af—4
