From Commit to Full Rollout: Building a Progressive Delivery Pipeline
You merge your code into the main branch. The CI pipeline turns green. The artifact is ready. Now what?
In most teams, the next step is simple: deploy to production. But if you have ever watched a deployment go wrong - a bug that only appears under real traffic, a performance regression that silently creeps in, a feature that confuses users - you know that "deploy to all users at once" is a gamble you don't have to take.
Progressive delivery changes that. Instead of one big switch, you roll out changes gradually, using traffic routing, feature flags, and automated monitoring to decide at each step whether to proceed or pull back. This article walks through how to assemble a complete progressive delivery pipeline, from the moment code is merged until the feature is fully live and stable.
The following flowchart shows the stages of the pipeline at a glance:
The Build and Basic Tests
The pipeline starts like any other. When a developer merges code into the main branch, the pipeline runs unit tests, integration tests, and security scans. These are the same checks you already have - nothing special yet.
If everything passes, the pipeline produces a deployable artifact. This is where progressive delivery begins to differ from a standard pipeline. The artifact does not go straight to all users. It enters the first deployment ring, typically called the canary ring.
The Canary Ring: Your First Real Test
The canary ring receives a small fraction of traffic - say, one percent of all requests. The pipeline deploys the new version to the servers that serve this ring. Then it activates the relevant feature flags for users who land in that ring.
Here is a GitLab CI example that defines the canary ring and staged rollout steps:
stages:
- canary
- staged-rollout
- full-rollout
canary-deploy:
stage: canary
script:
- kubectl set image deployment/my-app canary=my-app:$CI_COMMIT_SHA
- kubectl scale deployment/my-app --replicas=1
environment:
name: production/canary
url: https://canary.example.com
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
auto-promote:
stage: staged-rollout
script:
- sleep 600 # 10-minute monitoring window
- ./check-metrics.sh # verify error rate, latency within SLO
- kubectl set image deployment/my-app-10pct my-app=my-app:$CI_COMMIT_SHA
- kubectl scale deployment/my-app-10pct --replicas=2
needs: ["canary-deploy"]
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
rollout-50pct:
stage: staged-rollout
script:
- ./check-metrics.sh
- kubectl set image deployment/my-app-50pct my-app=my-app:$CI_COMMIT_SHA
needs: ["auto-promote"]
when: manual # requires manual approval
rollout-100pct:
stage: full-rollout
script:
- ./check-metrics.sh
- kubectl set image deployment/my-app my-app=$CI_COMMIT_SHA
needs: ["rollout-50pct"]
when: manual
Feature flags add an extra layer of control here. Even though the new version is running, specific features can be enabled only for certain users within the canary ring. This lets you test not just the stability of the new version, but also the behavior of a particular feature on real users, without exposing everyone to it.
While the new version runs in the canary ring, observability kicks in. The pipeline monitors error rate, latency, and other metrics defined in your Service Level Objectives (SLOs). If all metrics stay within acceptable bounds for a set period - say, ten minutes - the pipeline automatically proceeds to the next stage. If any metric violates the threshold, the pipeline triggers an automatic rollback: traffic shifts back to the old version, feature flags turn off, and the team gets notified.
Staged Rollout: Expanding the Audience
The next stage is a broader ring, perhaps serving ten percent of users. The process repeats: deploy, activate flags, monitor, decide. But now you have more room to experiment with feature flags. For example, you might enable the new feature only for users who registered as beta testers. This gives you real data from real users without impacting everyone.
The pipeline continues expanding the audience step by step: from ten percent to twenty-five percent, then to fifty percent, and finally to one hundred percent. Each time the pipeline moves to the next ring, it passes through a promotion gate. This gate can be an automated check based on metrics, or it can wait for manual approval from the team. Many teams use a combination: automated gates for quick decisions, and manual approval for critical stages, such as before going to one hundred percent of users.
Cleaning Up Feature Flags
Once the new version serves all users, the pipeline is not done. Feature flags that are now active for everyone need to be cleaned up. The pipeline can run a task that checks whether a flag is still in use, then creates a pull request to remove the flag code from the repository. This prevents your codebase from accumulating dead flags that nobody remembers.
What Makes This Pipeline Different
A progressive delivery pipeline is not just a sequence of deployments. It is a system that combines traffic management, feature control, automated monitoring, and data-driven decisions into a single flow that runs from commit to full rollout. Each stage is a safety layer that ensures changes do not suddenly break the user experience.
The key difference from a traditional pipeline is that you are not asking "did the build pass?" You are asking "is the change safe to expose to more users?" That question cannot be answered by unit tests alone. It requires real traffic, real users, and real metrics.
Practical Checklist for Your Pipeline
If you are building a progressive delivery pipeline, here are the components to verify at each stage:
- Canary ring: Does it receive a small, measurable fraction of traffic? Can you route users consistently so the same user stays in the same ring?
- Feature flags: Are flags scoped to specific users or groups? Can you toggle them independently of deployment?
- Observability: Are error rate, latency, and business metrics monitored? Are the thresholds based on your SLOs, not arbitrary guesses?
- Promotion gates: Does each ring have a clear condition to proceed? Is there a manual approval step for critical expansions?
- Rollback: Is rollback automated when metrics breach thresholds? Does it include both traffic routing and flag deactivation?
- Flag cleanup: Is there a process to remove flags after full rollout? Does the pipeline create a pull request or notify the team?
The Takeaway
A progressive delivery pipeline turns deployment from a binary event into a graduated process. You do not release a change and hope for the best. You release it to a small group, watch what happens, and decide whether to continue. If something goes wrong, only a tiny fraction of users are affected, and the system recovers automatically.
The pipeline is not about adding complexity. It is about adding control. Every ring, every gate, every metric check is a chance to catch a problem before it becomes an incident. Build your pipeline with that in mind, and you will sleep better after every merge.