An insurance company running on an IBM mainframe had accumulated forty years of policy data in VSAM files and DB2 tables. The mainframe processed 600,000 transactions per day across policy administration, claims processing, and billing. The system worked. The system was also forty years old, written in COBOL, maintained by a team of eight developers whose average age was sixty-one. The youngest COBOL developer on the team was fifty-four. The company’s board had approved a cloud migration five years earlier. Three outside firms had assessed the migration and concluded it was too risky to attempt while the mainframe was processing live transactions.
The risk assessment was correct. A big-bang migration — copy all data, rewrite all applications, switch over a weekend — was not feasible. The mainframe contained 1.2 billion policy records, 340 million claims records, and business logic encoded in 4.7 million lines of COBOL that no living person fully understood. A migration that stopped the mainframe for even one day would delay claims payments for 2.3 million active policyholders, trigger regulatory scrutiny, and cost approximately $4 million in operational disruption.
The question was not whether to migrate. The question was how to migrate without stopping the mainframe.
The strangler fig approach
We designed a migration using the strangler fig pattern — named after the tropical vine that grows around a tree, gradually replacing it without killing it. The cloud-native system grew around the mainframe, absorbing functionality one domain at a time while the mainframe continued to process live transactions. Over time, the cloud-native system handled an increasing share of the workload. The mainframe handled a decreasing share. The transition was measured in years, not months.
This diagram requires JavaScript.
Enable JavaScript in your browser to use this feature.
The routing layer was the hinge. Every transaction — a policy change, a claim submission, a billing adjustment — entered the routing layer. The router determined whether the transaction’s domain had been migrated to the cloud-native system or was still on the mainframe. Migrated transactions were routed to cloud-native services. Legacy transactions were routed to the mainframe. The policyholder experienced no difference regardless of which system processed their transaction.
The data sync service kept the two databases consistent. When a transaction was processed on the mainframe, the sync service replicated the relevant records to the cloud database. When a transaction was processed in the cloud, the sync service replicated the results back to the mainframe. This dual-write pattern was the highest-risk component in the architecture, because inconsistencies between the two databases could cause incorrect policy calculations or missed claims payments.
The sync problem
The data sync service was the source of the project’s three most significant incidents. The first incident occurred during month four, when a sync lag of forty-five seconds caused a billing adjustment made on the mainframe to be processed twice — once by the mainframe and once by the cloud billing service, which received the synced record and treated it as a new transaction. The duplicate billing affected 1,200 policyholders. The team resolved it by adding idempotency keys to every synced record, ensuring that a record processed by one system could not be re-processed when it synced to the other.
The second incident occurred during month nine, when a schema change on the mainframe added a field to the policy record without updating the sync service. The sync service dropped the new field during replication, causing cloud-native services to produce incorrect premium calculations for policies that had been updated on the mainframe after the schema change. The team resolved it by adding schema validation to the sync service, which detected and alerted on schema mismatches before they caused data loss.
The third incident occurred during month fourteen, when a network partition between the mainframe and the cloud environment caused a sync backlog that grew to six hours. During the backlog window, the two databases were inconsistent. A claims adjuster on the cloud system approved a claim based on policy data that had been updated on the mainframe four hours earlier. The update had changed the policy’s coverage limits. The approved claim exceeded the updated limits. The team resolved it by implementing a consistency check that blocked transactions in the cloud system when the sync backlog exceeded a fifteen-minute threshold.
These incidents taught the team that the sync service was not an infrastructure component. It was a critical business system that required the same monitoring, testing, and change management as the mainframe itself.
The migration sequence
We migrated by business domain, not by technical layer. The first domain was billing, because it had the fewest integrations with other domains and the most straightforward data model. Billing was migrated in month six. The second domain was policy administration, because it was the largest and most complex, and the team wanted billing’s operational experience before tackling it. Policy administration was migrated in month eighteen. Claims processing was last, because it had the most regulatory constraints and the most complex business logic. Claims was migrated in month thirty.
Each domain migration followed the same protocol. The cloud-native service was built and tested against production data replicated from the mainframe. The service ran in shadow mode for at least sixty days, processing the same transactions as the mainframe and comparing outputs. When the shadow comparison showed consistent agreement for sixty consecutive days, the routing layer was updated to send live traffic to the cloud service. The mainframe continued to receive the same transactions for an additional thirty days as a fallback. After thirty days of live operation without incident, the mainframe’s corresponding modules were decommissioned.
Total migration time was thirty months. The board had allocated three years. The project came in six months early, primarily because the billing migration went smoothly and gave the team confidence to accelerate the policy administration timeline.
What we gave up
The mainframe processed transactions in batch cycles — four batch windows per day. The cloud-native system processed transactions in real time. This was an improvement, not a trade-off. However, some downstream systems had been built to consume the mainframe’s batch output. These systems had to be re-engineered to consume real-time event streams. The re-engineering effort added four months to the claims migration timeline.
The second trade-off was operational knowledge. The COBOL developers understood the mainframe’s behavior in ways that no one understood the cloud-native system. Forty years of edge cases, regulatory patches, and business rule exceptions were encoded in the COBOL code. The migration team spent roughly twenty percent of their time reverse-engineering COBOL logic to ensure that the cloud-native implementation preserved every edge case. Some edge cases were discovered only after the cloud system went live and produced a different result than the mainframe for a rare transaction type.
The third trade-off was cost during the parallel-run period. Running both systems simultaneously was expensive — the mainframe’s operating costs continued, and the cloud infrastructure added new costs. Total infrastructure cost during the thirty-month migration was approximately double the steady-state cost of either system alone. The team accepted this because the alternative — a risky big-bang migration — could have cost far more in a single incident.
Results
After the migration was complete, annual infrastructure costs decreased by thirty-five percent compared to the mainframe. Transaction processing latency decreased from batch-cycle averages of six hours to real-time processing under 500ms. The development team grew from eight COBOL developers to fourteen engineers working on cloud-native services, with a median age of thirty-four. The company’s ability to respond to regulatory changes improved from an average of four months to three weeks, because cloud-native services could be updated and deployed in days rather than mainframe release cycles measured in quarters.
The decision heuristic
If your legacy system is too critical to stop and too old to maintain, do not attempt a big-bang migration. Build the replacement around the legacy system using the strangler fig pattern. Accept that the parallel-run period will be long, expensive, and operationally complex. The cost of running both systems is the insurance premium against a catastrophic migration failure. Migrate one domain at a time, validate each domain with a shadow-mode period measured in months, and do not decommission the legacy system’s corresponding module until the replacement has been in production without incident for at least thirty days. Patience is the strategy.