GitOps Promotion for a Small SaaS: From Image Build to Production Rollout
A release tag is a promise about what is running. It becomes awkward when the image, the GitOps manifest and the browser disagree about what that promise means.
Problem
The release flow needed to move images through staging and production without relying on someone remembering which cluster was updated and which one was not. It also needed to keep secrets out of the Git history while still making the rollout traceable.
Constraints and risks
The risks are familiar:
- Mutable tags can hide what is actually running.
- Manual hotfixes can drift away from Git.
- A broken rollout can make it unclear what version is safe to restore.
- Secrets need to stay encrypted and separate from the manifest shape.
Design / Investigation
The core idea is to treat the repository as the source of desired state and the image registry as the source of immutable application builds.
Example promotion shape:
image:
repository: example/app
tag: "2026-02-19-a1b2c3d"
I keep the tag immutable so a promotion is a deliberate change, not a moving pointer.
The rollout path is usually:
- Build the image.
- Push it to the registry.
- Update staging manifests.
- Verify staging.
- Promote the same image tag to production.
Implementation approach
I like to keep a promotion checklist next to the manifests:
| Step | What I verify |
|---|---|
| Build | The image builds cleanly and consistently |
| Push | The registry contains the exact tag I intend to deploy |
| Staging | The app starts, serves health checks, and reads its config |
| Secrets | Encrypted values are still encrypted in Git |
| Production | The same immutable tag reaches production |
| Rollback | I can revert to the last known-good tag quickly |
Argo CD or a similar controller can then do the repetitive syncing work while I focus on the promotion decision itself.
What I would do differently
I would make rollback evidence even more explicit, especially in environments where several versions may be tested close together. The safer the rollback path, the less likely it is that a release issue becomes a long debugging session.
I would also keep the deployment notes shorter and more mechanical. A promotion runbook is most useful when it can be followed under pressure.
The release rule
The current path builds an immutable image, writes the same tag into staging and production manifests, and verifies both the deployed config.js version and the rendered browser result. A recent marketing-site release made that distinction concrete: a successful rollout was not enough until the initial loader stopped blocking the final page in desktop and mobile checks.
I now treat promotion as a chain of evidence, not a button press. The extra verification takes minutes; reconstructing which version a user actually saw takes longer.