Why more concurrency doesn't mean a proportionally faster migration
Most migration tools let you choose how many files upload at once. Turning that number up feels like turning a dial. More workers should mean more speed. Up to a point, they do. Beyond that point, adding more concurrency often delivers very little, and it's worth understanding why before planning a migration window around it.
The instinct to add more workers
Bandwidth and migration speed are often confused. Concurrency is a separate factor altogether, and it catches people who've already realised that their internet connection isn't the limiting factor.
If four simultaneous uploads are working well, eight sounds like it should finish the migration in roughly half the time. Sixteen sounds faster again. It's a perfectly reasonable assumption.
The difficulty is that, beyond a certain point, the bottleneck usually isn't yours anymore.
Where the ceiling actually is
Microsoft 365 protects its own services by throttling requests when activity reaches certain thresholds. Once a tenant reaches those limits, Microsoft Graph begins returning HTTP 429 responses, instructing clients to slow down before trying again.
That's not an error. It's Microsoft ensuring one tenant can't consume a disproportionate share of shared resources.
Once throttling becomes the limiting factor, increasing concurrency no longer means proportionally more work gets done. It simply means more upload threads waiting for permission to continue.
What that looks like in practice
Testing against a real Microsoft 365 tenant showed exactly that behaviour. Increasing concurrency from a modest level produced a worthwhile improvement in throughput. Increasing it again beyond that point made very little difference to the overall completion time, while generating significantly more throttling responses.
The additional workers weren't failing. They simply spent more of their time waiting because Microsoft 365 wasn't prepared to accept requests any faster.
That's the signature of an external bottleneck rather than a local one. Adding more capacity on your side doesn't increase throughput because the constraint exists somewhere else.
Guessing versus responding
The awkward part is that there isn't a single ideal concurrency setting.
The right number depends on the tenant, the time of day, what other activity is happening within that Microsoft 365 tenant, and Microsoft's own service conditions at that moment.
A fixed configuration is therefore always a compromise. Set it conservatively and you leave performance on the table. Set it aggressively and you spend more time being throttled.
A better approach is to respond to what's actually happening instead of trying to predict it in advance.
Backing off automatically, then recovering
Liscaragh Migrate adjusts its upload concurrency automatically throughout a migration. When Microsoft 365 signals that requests are arriving too quickly, the number of simultaneous uploads is reduced immediately. If Microsoft specifies a retry delay, that delay is honoured before uploads continue. Once throttling subsides, concurrency gradually increases again without any manual intervention. Nothing needs restarting, nothing is retried from scratch, and no data is lost. Throttling is treated as an expected characteristic of large Microsoft 365 migrations rather than an unexpected failure.
What this means when planning a migration
Don't estimate a migration window by assuming that doubling concurrency will halve the migration time.
Increasing the number of simultaneous uploads genuinely helps until another constraint takes over. Beyond that point, the only reliable way to estimate completion time is to measure real throughput against the actual Microsoft 365 tenant you're migrating into.
The question worth asking
If increasing concurrency no longer makes a migration noticeably faster, you've probably stopped being limited by your own infrastructure.
At that point, the question isn't how many more workers you can add. It's whether Microsoft 365 is already telling you to slow down.