Keep one public entry point, make the legacy system reachable only through it, log both paths in the same place, and track a shrinking list of routes still served by old code. Parallel running is safe when each old route has an owner and an end date.
Why parallel running is unavoidable
Gradual migration means old and new coexist. Microsoft's guidance on the strangler fig pattern says the original system can continue to exist for an extended period of time, and that you should plan for cross system dependencies. A parallel run may last months or years, so treat it as an operating mode, not a brief phase.
The risks of running both
- Two sets of dependencies to patch
- Two authentication paths, which may disagree
- Data written by both systems, which may diverge
- Monitoring split across tools, so incidents are harder to trace
- Teams losing track of which route is served by which system
Controls
- One front door. All client traffic enters through the facade. Block direct access to the legacy application at the network level.
- Common identity. Use the same identity provider for both paths and propagate the user identity to each backend.
- Unified logging. Send logs from both systems to one place with a common request identifier and a field showing which backend served the request.
- Same baseline controls. Rate limits, input size limits and security headers apply to both routes.
- A route register. A simple table lists every route, its backend, owner and target cutover date.
- Regular review. Check the register every sprint. Overdue routes need a decision.
| Route | Backend | Owner | Cutover target |
|---|---|---|---|
| /orders | New service | Orders team | Done |
| /invoices | Legacy | Billing team | Set a date |
| /reports | Legacy | Platform | Set a date |
Data consistency
If both systems can write the same data, decide which is the source of truth for each entity and enforce it. A common approach is to switch writes first for one entity at a time, with reads served from the new store once it matches. Test the switch in a staging environment with realistic data, and keep a rollback plan.
Security testing in parallel
Run the same security tests against both versions of a route. Differences are findings. If the new service rejects a request that legacy accepted, find out whether that is a bug or a fixed weakness. If legacy rejects something the new service accepts, you may have regressed.
Watch the clock
The longer a legacy component stays, the more advisories accumulate against its libraries. Plan to reduce reachable exposure at each step instead of waiting for the end. Use reachability to patch what matters and delete what is dead. Our post on legacy software supply chain risks gives more context on the legacy side.
Try it yourself
Click through it at your own pace, or open it full screen.
Watch how new advisories surface against components already in your inventory. That is what keeps the legacy side honest during a long parallel run.
Safeguard's continuous scanning and policies cover repositories on both sides in one inventory.
Quick check
Can the legacy app keep its own login?
Only temporarily, and only behind the facade. Plan to move it to the shared identity provider.
How long is too long for a parallel run?
There is no fixed number. Overdue cutover dates in the route register are the signal to decide.
Sources
Last reviewed: 19 October 2026.