A rewrite isn't a code project. It's a traffic migration project, and the code is the part you finish first.
The new system is the easy half: you know the requirements, and you've already watched the old one fail. What hurts is the months where both systems are alive and money, orders, or signed documents move through both. Five questions worth answering before anyone writes a line.
What is the unit of ownership I can move? Not "the service": a tenant, an account, a merchant, a region. If you can't name the key that decides which system owns a given record, you don't have a cutover, you have a launch date.
Who mints identifiers after the split? Two systems generating IDs over the same domain is permanent reconciliation work. One side owns identity, the other borrows it.
How do I compare the two? Shadow the reads. Send real traffic to both, diff the responses, log the mismatches without serving them. Passing tests tell you the new code works. The diff tells you it agrees with the system people already depend on.
When does rollback stop being a deploy? The first write that lands only in the new store turns rollback from a redeploy into a data migration. That moment belongs in the plan and not in the incident channel.
Which legacy behavior is a bug, and which one is a contract? Somebody downstream built on the rounding, the ordering, the extra whitespace, the empty list that should have been an error. Removing it is a breaking change even when the ticket calls it a fix.
None of these are architecture questions. They're seam questions, and the seam is where rewrites actually die. The teams I've seen get through a modernization cleanly spent their first weeks designing the coexistence period rather than the end state.
I went deeper on how I plan these migrations here: https://polycratia.com/c/ba70db33
If you've run a long cutover, I'd like to hear what forced you to keep the old system alive longer than you planned.