For any team planning a hosting-platform shift at scale, the instructive part of GitHub's recent work is not the destination but the ordering of moves: durable state first, consensus and topology changes afterward. Over the past year, Git traffic rose so steeply that 99.99999% of repositories ended up resident in two places at once — GitHub facilities and Azure. The residual 0.00001% is no technical afterthought; it concentrates in the busiest repositories on the platform, and one obstacle alone kept them out of the target region: a 25ms round trip.
The whole effort is organized around two principles that map directly onto enterprise cloud design work:
The shape of the plan came from constraints rather than preference: fast traffic growth, a hard ceiling on power capacity in the data centers and the neighboring region, plus physical supply chain constraints. Capacity on hand at the start, together with every expansion that could be arranged, was enough to migrate safely — but not enough to migrate slowly.
New Git scaling designs on cloud infrastructure had already been prototyped. Changing storage architecture and hosting platform inside the same window, while traffic kept climbing, was still judged too risky. Because GitHub matters deeply to the community, the order of operations was fixed early: move data first, then evolve architecture after arrival.
Repository operations are a Tier 0 service — core GitHub functions that nearly everything else depends on — so data, services and dependencies had to leave first. The first repository copy landed in Azure Central US in August 2025. Most repositories now keep two of their five replicas in Azure, and Azure handles about half of Git traffic. Through much of that period Azure absorbed growth while the older data centers stayed level.
Each repository normally keeps five replicas to balance durability, availability and scale, and Spokes uses preferential routing to reach a replica in the same region and availability zone as the request, lowering read latency. As every replica migrates, the share of requests Azure can serve grows until the final one arrives and the old region stops receiving traffic. During the whole migration, traffic followed the data.
Under the previous architecture, a repository hosted in more than one region had a lower ceiling for write throughput. The Spokes quorum only needs a majority to commit a write, yet it waits for every healthy replica to answer, up to a timeout, before continuing — so slow replicas delayed every write instead of merely falling behind.
Because each write held a repository-wide lock until commit, the slowest healthy replica also fixed the throughput ceiling. With a replica sitting in the target Azure region about 1,000 miles from the older data centers, cross-region delay becomes a 25ms round trip, and a single write needs several trips. A repository already near its ceiling cannot absorb that penalty on every serialized write; it would fall further behind with every push.
Minimizing coordination means refusing to serialize what does not need serializing. Git consistency rules attach to each reference separately: once the server accepts a reference update, no client should later see an older value, only that value or a newer one. The rule applies whether the update is a fast-forward, a force push or a delete, and in most cases different references can be updated independently. The quorum scope therefore shifted from the entire repository to individual references.
Holding a repository-wide lock through an update, round trips included, makes the quorum behave like one unordered request queue with one write in flight at a time. Each queued write lasts as long as the slowest healthy replica; as the write rate rises, the queue lengthens and every write waits longer than the previous one.
| Serialization scope | Queue behavior | Write overlap |
|---|---|---|
| Repository-wide | one write in flight at a time | none |
| Per-reference | only writes contending on shared references wait | different references overlap |
Per-reference serialization narrows waiting to writes that contend on the same reference. In practice most repository writes touch different references — agents and developers pushing their own branches — so they no longer block one another. The cross-region latency cost per write remains, but concurrent references move at the same time, removing the single repository-wide bottleneck. The adjustment lifts a repository's write throughput ceiling in proportion to the number of references updated concurrently, which is what finally moved the last remaining repositories into Azure. In internal testing with realistic traffic, writes to different references consistently saw 3–4x higher throughput at lower latency.
Most repositories are heavily read-skewed, with somewhere between 100 and 1,000 reads for every write. While reads and writes use the same replicas, they compete for the same resources and cannot be scaled independently.
Decoupling storage from compute changes that. Once repository data is durably stored in Azure Blob Storage and updated with each incoming write, read traffic can be separated from the write quorum and the compute for each role scaled on its own. Reads would benefit from far more in-memory cache, but that memory is also needed for compaction; once split, each role can have its own configuration.
The initial step makes object storage a quorum member through a virtual replica, and the compute standing for it is the first fully ephemeral node. It bridges to object storage, streams incoming writes and serves no reads. Because it belongs to the quorum, a write is not acknowledged until the data is durable in object storage.
That adds a little write latency. As with cross-region round trips, per-reference serialization prevents the latency from becoming a throughput bottleneck: the virtual write replica coalesces transactions on disjoint references into one set of network I/Os to object storage, so a busy repository pays for one round trip across many concurrent writes instead of one per write. For now the virtual write replica also performs compaction, and read replicas inherit the compacted state.
With that replica in place, many virtual read replicas can be scaled out as a repository needs them. Each read replica warms its cache from Azure Blob Storage and starts taking read traffic without joining the quorum, using object storage as the source of truth and reconciling its local state against it in the background. This is where the read scale headroom shows up: in internal testing the distributed load testing harness routinely found ceilings in the previous architecture, while against virtual read replicas the harness hit its own limits first.
Two caveats carry forward. Background reconciliation suits some read workloads but not all, and serving every kind of read requires moving that reconciliation in-line, fetching only the reference state and data that changed since the replica last caught up. And although per-reference serialization raised write throughput incrementally, the quorum remains the bounding factor for further growth.
Because that remainder sits among the busiest repositories, where a repository-wide serialized lock combined with a cross-region 25ms round trip fixes a throughput ceiling that a near-saturated repository cannot absorb.
The serialization scope: the quorum locks individual references instead of the entire repository, so writes touching different references overlap rather than queue.
No. Write headroom came from per-reference serialization; read scale came separately, once data was durable in Azure Blob Storage and virtual read replicas could warm caches and take traffic without joining the quorum.
Not yet. Write throughput is the next limit: every write still waits on replicas that each hold a full copy of the repository, while very little of a write actually needs ordering.
The layer that made all of this possible has outgrown its original role. Over the years Spokes became an intelligent routing and load balancing layer, a unified API used by internal clients to access and transact repository data at well over 100 billion operations per day, and background systems called 'sweepers' that handle repository placement, repair and rebalancing between storage nodes. Most of the work under that umbrella also fits the new architecture.
The commit protocol that carried GitHub to a billion repositories will not carry it to the next billion and beyond. Git objects are immutable and named by their contents, so they can be stored without anyone agreeing on them; what remains is small, and the hard part is ordering it as quickly as possible without moving the bottleneck elsewhere. Designing that on a whiteboard is one thing — doing it underneath live repositories that developers and agents write to around the clock is another, and reaching that state forced a rethink of second-order effects such as where durable reference state lives and how compaction and garbage collection scale. Agent traffic is not slowing, and each step gives repositories more headroom as it lands, without waiting for the end state.
For readers tracking the series, the tour covers that end state next week, at GitHub Universe and in the final post: what it does for write throughput, the second-order problems that had to be solved to reach it, and why a small consensus group remains somewhere in the stack. Editorial by James Hartley, IT Insights. Brian Celenza contributed to this post. For cloud architecture coverage or corrections, contact contact@itinsights.com.