This is the multi-page printable view of this section.
Click here to print.
Return to the regular view of this page.
Migrating Brownfield to CD
Already have a running system? A phased approach to migrating existing applications and teams to continuous delivery.
Most teams adopting CD are not starting from scratch. They have existing codebases, existing
processes, existing habits, and existing pain. This section provides the phased migration path
from where you are today to continuous delivery, without stopping feature delivery along the way.
The Reality of Brownfield Migration
Migrating an existing system to CD is harder than building CD into a greenfield project. You are
working against inertia: existing branching strategies, existing test suites (or lack thereof),
existing deployment processes, and existing team habits. Every change has to be made incrementally,
alongside regular delivery work.
The good news: every team that has successfully adopted CD has done it this way. The practices in
this guide are designed for incremental adoption, not big-bang transformation.
The Migration Phases
The migration is organized into five phases. Each phase builds on the previous one. Start with
Phase 0 to understand where you are, then work through the phases in order.
| Phase |
Name |
Goal |
Key Question |
| 0 |
Assess |
Understand where you are |
“How far are we from CD?” |
| 1 |
Foundations |
Daily integration, testing, small work |
“Can we integrate safely every day?” |
| 2 |
Pipeline |
Automated path to production |
“Can we deploy any commit automatically?” |
| 3 |
Optimize |
Improve flow, reduce batch size |
“Can we deliver small changes quickly?” |
| 4 |
Deliver on Demand |
Deploy any change when needed |
“Can we deliver any change to production when needed?” |
Where to Start
If you don’t know where you stand
Start with Phase 0 - Assess. Complete the value stream mapping exercise, take
baseline metrics, and fill out the current-state checklist. These activities tell you exactly
where you stand and which phase to begin with.
If you know your biggest pain point
Start with Anti-Patterns. Find the problem your team feels most, and follow the
links to the practices and migration phases that address it.
Quick self-assessment
If you don’t have time for a full assessment, answer these questions:
- Do all developers integrate to trunk at least daily? If no, start with
Phase 1.
- Do you have a single automated pipeline that every change goes through? If no, start with
Phase 2.
- Can you deploy any green build to production on demand? If no, focus on the gap between
your current state and Phase 2 completion criteria.
- Do you deploy at least weekly? If no, look at Phase 3 for batch size and
flow optimization.
Principles for Brownfield Migration
Do not stop delivering features
The migration is done alongside regular delivery work, not instead of it. Each practice is adopted
incrementally. You do not stop the world to rewrite your test suite or redesign your pipeline.
Fix the biggest constraint first
Use your value stream map and metrics to identify which blocker is the current constraint. Fix
that one thing. Then find the next constraint and fix that. Do not try to fix everything at once.
See Identify Constraints and the
CD Dependency Tree.
Make progress visible
Track your DORA metrics from day one: deployment frequency, lead time for changes, change failure
rate, and mean time to restore. These metrics show whether your changes are working and build the
case for continued investment.
See Baseline Metrics.
Start with one team
CD adoption works best when a single team can experiment, learn, and iterate without waiting for
organizational consensus. Once one team demonstrates results, other teams have a concrete example
to follow.
Common Brownfield Challenges
These challenges are specific to migrating existing systems. For the full catalog of problems
teams face, see Anti-Patterns.
| Challenge |
Why it’s hard |
Approach |
| Large codebase with no tests |
Writing tests retroactively is expensive and the ROI feels unclear |
Do not try to add tests to the whole codebase. Add tests to every file you touch. Use the test-for-every-bug-fix rule. Coverage grows where it matters most. |
| Long-lived feature branches |
The team has been using feature branches for years and the workflow feels safe |
Reduce branch lifetime gradually: from two weeks to one week to two days to same-day. Do not switch to trunk overnight. |
| Manual deployment process |
The “deployment expert” has a 50-step runbook in their head |
Document the manual process first. Then automate one step at a time, starting with the most error-prone step. |
| Flaky test suite |
Tests that randomly fail have trained the team to ignore failures |
Quarantine all flaky tests immediately. They do not block the build until they are fixed. Zero tolerance for new flaky tests. |
| Tightly coupled architecture |
Changing one module breaks others unpredictably |
You do not need microservices. You need clear boundaries. Start by identifying and enforcing module boundaries within the monolith. |
| Organizational resistance |
“We’ve always done it this way” |
Start small, show results, build the case with data. One team deploying daily with lower failure rates is more persuasive than any slide deck. |
Migration Timeline
These ranges assume a single team working on the migration alongside regular delivery work:
| Phase |
Typical Duration |
Biggest Variable |
| Phase 0 - Assess |
1-2 weeks |
None - just do it |
| Phase 1 - Foundations |
1-6 months |
Current testing and trunk-based development maturity |
| Phase 2 - Pipeline |
1-3 months |
Complexity of existing deployment process |
| Phase 3 - Optimize |
2-6 months |
Organizational willingness to change batch size and approval processes |
| Phase 4 - Deliver on Demand |
1-3 months |
Confidence in pipeline and rollback capability |
Do not treat these timelines as commitments. The migration is an iterative improvement process,
not a project with a deadline.
Related Content
1 - Document Your Current Process
Before formal value stream mapping, get the team to write down every step from “ready to push” to “running in production.” Quick wins surface immediately; the documented process becomes better input for the value stream mapping session.
The Brownfield CD overview covers the migration phases, principles, and common challenges.
This page covers the first practical step - documenting what actually happens today between a
developer finishing a change and that change running in production.
Why Document Before Mapping
Value stream mapping is a powerful tool for systemic improvement. It requires measurement, cross-team
coordination, and careful analysis. That takes time to do well, and it should not be rushed.
But you do not need a value stream map to spot obvious friction. Manual steps that could be
automated, wait times caused by batching, handoffs that exist only because of process - these
are visible the moment you write the process down.
Document your current process first. This gives you two things:
- Quick wins you can fix this week. Obvious waste that requires no measurement or
cross-team coordination to remove.
- Better input for value stream mapping. When you do the formal mapping session, the team
is not starting from a blank whiteboard. They have a shared, written description of what
actually happens, and they have already removed the most obvious friction.
Quick wins build momentum. Teams that see immediate improvements are more willing to invest in
the deeper systemic work that value stream mapping reveals.
How to Do It
Get the team together. Pick a recent change that went through the full process from “ready to
push” to “running in production.” Walk through every step that happened, in order.
The rules:
- Document what actually happens, not what should happen. If the official process says
“automated deployment” but someone actually SSH-es into a server and runs a script, write
down the SSH step.
- Include the invisible steps. The Slack message asking for review. The email requesting
deploy approval. The wait for the Tuesday deploy window. These are often the biggest sources
of delay and they are usually missing from official process documentation.
- Get the whole team in the room. Different people see different parts of the process. The
developer who writes the code may not know what happens after the merge. The ops person who
runs the deploy may not know about the QA handoff. You need every perspective.
- Write it down as an ordered list. Not a flowchart, not a diagram, not a wiki page with
sections. A simple numbered list of steps in the order they actually happen.
What to Capture for Each Step
For every step in the process, capture these details:
| Field |
What to Write |
Example |
| Step name |
What happens, in plain language |
“QA runs manual regression tests” |
| Who does it |
Person or role responsible |
“QA engineer on rotation” |
| Manual or automated |
Is this step done by a human or by a tool? |
“Manual” |
| Typical duration |
How long the step itself takes |
“4 hours” |
| Wait time before it starts |
How long the change sits before this step begins |
“1-2 days (waits for QA availability)” |
| What can go wrong |
Common failure modes for this step |
“Tests find a bug, change goes back to dev” |
The wait time column is usually more revealing than the duration column. A deploy that takes 10
minutes but only happens on Tuesdays has up to 7 days of wait time. The step itself is not the
problem - the batching is.
Example: A Typical Brownfield Process
This is a realistic example of what a brownfield team’s process might look like before any CD
practices are adopted. Your process will differ, but the pattern of manual steps and wait times
is common.
| # |
Step |
Who |
Manual/Auto |
Duration |
Wait Before |
What Can Go Wrong |
| 1 |
Push to feature branch |
Developer |
Manual |
Minutes |
None |
Merge conflicts with other branches |
| 2 |
Open pull request |
Developer |
Manual |
10 min |
None |
Forgot to update tests |
| 3 |
Wait for code review |
Developer (waiting) |
Manual |
- |
4 hours to 2 days |
Reviewer is busy, PR sits |
| 4 |
Address review feedback |
Developer |
Manual |
30 min to 2 hours |
- |
Multiple rounds of feedback |
| 5 |
Merge to main branch |
Developer |
Manual |
Minutes |
- |
Merge conflicts from stale branch |
| 6 |
CI runs (build + unit tests) |
CI server |
Automated |
15 min |
Minutes |
Flaky tests cause false failures |
| 7 |
QA picks up ticket from board |
QA engineer |
Manual |
- |
1-3 days |
QA backlog, other priorities |
| 8 |
Manual functional testing |
QA engineer |
Manual |
2-4 hours |
- |
Finds bug, sends back to dev |
| 9 |
Request deploy approval |
Team lead |
Manual |
5 min |
- |
Approver is on vacation |
| 10 |
Wait for deploy window |
Everyone (waiting) |
- |
- |
1-7 days (deploys on Tuesdays) |
Window missed, wait another week |
| 11 |
Ops runs deployment |
Ops engineer |
Manual |
30 min |
- |
Script fails, manual rollback |
| 12 |
Smoke test in production |
Ops engineer |
Manual |
15 min |
- |
Finds issue, emergency rollback |
Total typical time: 3 to 14 days from “ready to push” to “running in production.”
Even before measurement or analysis, patterns jump out:
- Steps 3, 7, and 10 are pure wait time - nothing is happening to the change.
- Steps 8 and 12 are manual testing that could potentially be automated.
- Step 10 is artificial batching - deploys happen on a schedule, not on demand.
- Step 9 might be a rubber-stamp approval that adds delay without adding safety.
Spotting Quick Wins
Once the process is documented, look for these patterns. Each one is a potential quick win that
the team can fix without a formal improvement initiative.
Automation targets
Steps that are purely manual but have well-known automation:
- Code formatting and linting. If reviewers spend time on style issues, add a linter to CI.
This saves reviewer time on every single PR.
- Running tests. If someone manually runs tests before merging, make CI run them
automatically on every push.
- Build and package. If someone manually builds artifacts, automate the build in the
pipeline.
- Smoke tests. If someone manually clicks through the app after deploy, write a small set
of automated smoke tests.
Batching delays
Steps where changes wait for a scheduled event:
- Deploy windows. “We deploy on Tuesdays” means every change waits an average of 3.5 days.
Moving to deploy-on-demand (even if still manual) removes this wait entirely.
- QA batches. “QA tests the release candidate” means changes queue up. Testing each change
as it merges removes the batch.
- CAB meetings. “The change advisory board meets on Thursdays” adds up to a week of wait
time per change.
Process-only handoffs
Steps where work moves between people not because of a skill requirement, but because of
process:
- QA sign-off that is a rubber stamp. If QA always approves and never finds issues, the
sign-off is not adding value.
- Approval steps that are never rejected. Track the rejection rate. If an approval step
has a 0% rejection rate over the last 6 months, it is ceremony, not a gate.
- Handoffs between people who sit next to each other. If the developer could do the step
themselves but “process says” someone else has to, question the process.
Unnecessary steps
Steps that exist because of historical reasons and no longer serve a purpose:
- Manual steps that duplicate automated checks. If CI runs the tests and someone also runs
them manually “just to be sure,” the manual run is waste.
- Approvals for low-risk changes. Not every change needs the same level of scrutiny. A
typo fix in documentation does not need a CAB review.
Quick Wins vs. Value Stream Improvements
Not everything you find in the documented process is a quick win. Distinguish between the two:
|
Quick Wins |
Value Stream Improvements |
| Scope |
Single team can fix |
Requires cross-team coordination |
| Timeline |
Days to a week |
Weeks to months |
| Measurement |
Obvious before/after |
Requires baseline metrics and tracking |
| Risk |
Low - small, reversible changes |
Higher - systemic process changes |
| Examples |
Add linter to CI, remove rubber-stamp approval, enable on-demand deploys |
Restructure testing strategy, redesign deployment pipeline, change team topology |
Do the quick wins now. Do not wait for the value stream mapping session. Every manual step
you remove this week is one less step cluttering the value stream map and one less source of
friction for the team.
Bring the documented process to the value stream mapping session. The team has already
aligned on what actually happens, removed the obvious waste, and built some momentum. The value
stream mapping session can focus on the systemic issues that require measurement, cross-team
coordination, and deeper analysis.
What Comes Next
- Fix the quick wins. Assign each one to someone with a target of this week or next week.
Do not create a backlog of improvements that sits untouched.
- Schedule the value stream mapping session. Use the documented process as the starting
point. See Value Stream Mapping.
- Start the replacement cycle. For manual validations that are not quick wins, use the
Replacing Manual Validations cycle to systematically
automate and remove them.
Related Content
2 - Replacing Manual Validations with Automation
The repeating mechanical cycle at the heart of every brownfield CD migration: identify a manual validation, automate it, prove the automation works, and remove the manual step.
The Brownfield CD overview covers the migration phases, principles, and common challenges.
This page covers the core mechanical process - the specific, repeating cycle of replacing
manual validations with automation that drives every phase forward.
The Replacement Cycle
Every brownfield CD migration follows the same four-step cycle, repeated until no manual
validations remain between commit and production:
- Identify a manual validation in the delivery process.
- Automate the check so it runs in the pipeline without human intervention.
- Validate that the automation catches the same problems the manual step caught.
- Remove the manual step from the process.
Then pick the next manual validation and repeat.
Two rules make this cycle work:
- Do not skip “validate.” Run the manual and automated checks in parallel long enough to
prove the automation catches what the manual step caught. Without this evidence, the team will
not trust the automation, and the manual step will creep back.
- Do not skip “remove.” Keeping both the manual and automated checks adds cost without
removing it. The goal is replacement, not duplication. Once the automated check is proven,
retire the manual step explicitly.
Inventory Your Manual Validations
Before you can replace manual validations, you need to know what they are. A
value stream map is the fastest way to find them. Walk the
path from commit to production and mark every point where a human has to inspect, approve, verify,
or execute something before the change can move forward.
Common manual validations and where they typically live:
| Manual Validation |
Where It Lives |
What It Catches |
| Manual regression testing |
QA team runs test cases before release |
Functional regressions in existing features |
| Code style review |
PR review checklist |
Formatting, naming, structural consistency |
| Security review |
Security team sign-off before deploy |
Vulnerable dependencies, injection risks, auth gaps |
| Environment configuration |
Ops team configures target environment |
Missing env vars, wrong connection strings, incorrect feature flags |
| Smoke testing |
Someone clicks through the app after deploy |
Deployment-specific failures, broken integrations |
| Change advisory board |
CAB meeting approves production changes |
Risk assessment, change coordination, rollback planning |
| Database migration review |
DBA reviews and runs migration scripts |
Schema conflicts, data loss, performance regressions |
Your inventory will include items not on this list. That is expected. The list above covers the
most common ones, but every team has process-specific manual steps that accumulated over time.
Prioritize by Effort and Friction
Not all manual validations are equal. Some cause significant delay on every release. Others are
quick and infrequent. Prioritize by mapping each validation on two axes:
Friction (vertical axis - how much pain the manual step causes):
- How often does it run? (every commit, every release, quarterly)
- How long does it take? (minutes, hours, days)
- How often does it produce errors? (rarely, sometimes, frequently)
High-frequency, long-duration, error-prone validations cause the most friction.
Effort to automate (horizontal axis - how hard is the automation):
- Is the codebase ready? (clean interfaces vs. tightly coupled)
- Do tools exist? (linters, test frameworks, scanning tools)
- Is the validation well-defined? (clear pass/fail vs. subjective judgment)
Start with high-friction, low-effort validations. These give you the fastest return and build
momentum for harder automations later. This is the same constraint-based thinking described in
Identify Constraints - fix the biggest bottleneck first.
|
Low Effort |
High Effort |
| High Friction |
Start here - fastest return |
Plan these - high value but need investment |
| Low Friction |
Do these opportunistically |
Defer - low return for high cost |
Walkthrough: Replacing Manual Regression Testing
A concrete example of the full cycle applied to a common brownfield problem.
Starting state
The QA team runs 200 manual test cases before every release. The full regression suite takes three
days. Releases happen every two weeks, so the team spends roughly 20% of every sprint on manual
regression testing.
Step 1: Identify
The value stream map shows the 3-day manual regression cycle as the single largest wait time
between “code complete” and “deployed.” This is the constraint.
Step 2: Automate (start small)
Do not attempt to automate all 200 test cases at once. Rank the test cases by two criteria:
- Failure frequency: Which tests actually catch bugs? (In most suites, a small number of
tests catch the majority of real regressions.)
- Business criticality: Which tests cover the highest-risk functionality?
Pick the top 20 test cases by these criteria. Write automated tests for those 20 first. This is
enough to start the validation step.
Step 3: Validate (parallel run)
Run the 20 automated tests alongside the full manual regression suite for two or three release
cycles. Compare results:
- Did the automated tests catch the same failures the manual tests caught?
- Did the automated tests miss anything the manual tests caught?
- Did the automated tests catch anything the manual tests missed?
Track these results explicitly. They are the evidence the team needs to trust the automation.
Step 4: Remove
Once the automated tests have proven equivalent for those 20 test cases across multiple cycles,
remove those 20 test cases from the manual regression suite. The manual suite is now 180 test
cases - taking roughly 2.7 days instead of 3.
Repeat
Pick the next 20 highest-value test cases. Automate them. Validate with parallel runs. Remove the
manual cases. The manual suite shrinks with each cycle:
| Cycle |
Manual Test Cases |
Manual Duration |
Automated Tests |
| Start |
200 |
3.0 days |
0 |
| 1 |
180 |
2.7 days |
20 |
| 2 |
160 |
2.4 days |
40 |
| 3 |
140 |
2.1 days |
60 |
| 4 |
120 |
1.8 days |
80 |
| 5 |
100 |
1.5 days |
100 |
Each cycle also gets faster because the team builds skill and the test infrastructure matures.
For more on structuring automated tests effectively, see
Testing Fundamentals and
Functional Testing.
When Refactoring Is a Prerequisite
Sometimes you cannot automate a validation because the code is not structured for it. In these
cases, refactoring is a prerequisite step within the replacement cycle - not a separate initiative.
| Code-Level Blocker |
Why It Prevents Automation |
Refactoring Approach |
| Tight coupling between modules |
Cannot test one module without setting up the entire system |
Extract interfaces at module boundaries so modules can be tested in isolation |
| Hardcoded configuration |
Cannot run the same code in test and production environments |
Extract configuration into environment variables or config files |
| No clear entry points |
Cannot call business logic without going through the UI |
Extract business logic into callable functions or services |
| Shared mutable state |
Test results depend on execution order and are not repeatable |
Isolate state by passing dependencies explicitly instead of using globals |
| Scattered database access |
Cannot test logic without a running database and specific data |
Consolidate data access behind a repository layer that can be substituted in tests |
The key discipline: refactor only the minimum needed for the specific validation you are
automating. Do not expand the refactoring scope beyond what the current cycle requires. This keeps
the refactoring small, low-risk, and tied to a concrete outcome.
For more on decoupling strategies, see
Architecture Decoupling.
The Compounding Effect
Each completed replacement cycle frees time that was previously spent on manual validation. That
freed time becomes available for the next automation cycle. The pace of migration accelerates as
you progress:
| Cycle |
Manual Time per Release |
Time Available for Automation |
Cumulative Automated Checks |
| Start |
5 days |
Limited (squeezed between feature work) |
0 |
| After 2 cycles |
4 days |
1 day freed |
2 validations automated |
| After 4 cycles |
3 days |
2 days freed |
4 validations automated |
| After 6 cycles |
2 days |
3 days freed |
6 validations automated |
| After 8 cycles |
1 day |
4 days freed |
8 validations automated |
Early cycles are the hardest because you have the least available time. This is why starting with
the highest-friction, lowest-effort validation matters - it frees the most time for the least
investment.
The same compounding dynamic applies to
small batches - smaller changes are easier to validate, which
makes each cycle faster, which enables even smaller changes.
Small Steps in Everything
The replacement cycle embodies the same small-batch discipline that CD itself requires. The
principle applies at every level of the migration:
- Automate one validation at a time. Do not try to build the entire pipeline in one sprint.
- Refactor one module at a time. Do not launch a “tech debt initiative” to restructure the
whole codebase before you can automate anything.
- Remove one manual check at a time. Do not announce “we are eliminating manual QA” and try
to do it all at once.
The risk of big-step migration:
- The work stalls because the scope is too large to complete alongside feature delivery.
- ROI is distant because nothing is automated until everything is automated.
- Feature delivery suffers because the team is consumed by a transformation project instead of
delivering value.
This connects directly to the brownfield migration principle:
do not stop delivering features. The replacement cycle is designed to produce value at every
iteration, not only at the end.
For more on decomposing work into small steps, see
Work Decomposition.
Measuring Progress
Track these metrics to gauge migration progress. Start collecting them from
baseline before you begin replacing validations.
| Metric |
What It Tells You |
Target Direction |
| Manual validations remaining |
How many manual steps still exist between commit and production |
Down to zero |
| Time spent on manual validation per release |
How much calendar time manual checks consume each release cycle |
Decreasing each quarter |
| Pipeline coverage % |
What percentage of validations are automated in the pipeline |
Increasing toward 100% |
| Deployment frequency |
How often you deploy to production |
Increasing |
| Lead time for changes |
Time from commit to production |
Decreasing |
If manual validations remaining is decreasing but deployment frequency is not increasing, you may
be automating low-friction validations that are not on the critical path. Revisit your
prioritization and focus on the validations that are actually blocking faster delivery.
Related Content