How does GitHub move a billion repositories without stopping the service?

GitHub has copied 99.99999% of its repositories to Azure. The last fraction stays behind because of a 25-millisecond network round trip.

Why the move started

The timing and shape of the migration were driven by the agentic shift: rapidly growing traffic, a hard ceiling on the power capacity of GitHub's data centers and the surrounding geographical region, and physical supply chain constraints. At the beginning, the remaining capacity with all possible expansion gave enough time to migrate safely, but not enough to do it slowly. Git operations are a Tier 0 service. Nearly everything in GitHub depends on the repository data. That meant the data, services, and every dependency had to move first. The first copy landed in Azure's Central US region in August 2025. Today, most repositories have two of their five replicas in Azure, and Azure serves about half of Git traffic. For most of that time, Azure absorbed growth while the original data centers held steady. The move is not finished.

The bottleneck that held back the busiest repositories

In the current architecture, a repository hosted in more than one region has a lower write throughput ceiling. Spokes' quorum only needs a majority to commit a write, but it waits for every healthy replica to respond before moving on. The slowest healthy replica sets the latency of every write. Because each write holds a repository-wide lock until it commits, that replica also sets the throughput ceiling. Once a replica lives in the target Azure region, it is about 1,000 miles from the data centers. Each network round trip takes around 25ms, and a write requires multiple round trips. A repository already near its throughput ceiling cannot absorb that on every serialized write. It would fall further behind with every push.

Per-reference quorums unblock writes

Git's consistency requirements apply to each reference individually. Once the server accepts an update to a reference, no client should see an older value afterward. That holds whether the update is a fast-forward or a force push. It also holds for a delete. But updates to different references do not depend on each other and can be applied independently. GitHub is changing the scope of the quorum from the whole repository to individual references. Holding a repository-wide lock for the entire reference update turns the quorum into a single, unordered request queue with one write in flight at a time. With per-reference serialization, only writes that contend on a shared reference must wait for each other. In practice, most writes to a repository touch different references — agents and developers pushing to their own branches — so they no longer wait on each other. Each write still experiences the cross-region latency, but writes to different references can be in flight at the same time. That removes the single bottleneck on the repository. In internal testing with realistic traffic, writes to different references consistently saw 3–4x higher throughput at lower latency.

Read scaling through virtual replicas

Most repositories are heavily read-skewed, with somewhere between 100 and 1,000 reads for every write. Today, reads and writes hit the same replicas, so they compete for the same resources and cannot be scaled independently. Once repository data is durably stored in Azure Blob Storage and updated with each incoming write, read traffic can be decoupled from the write quorum. The first step is making object storage a member of the quorum — a special member called a virtual replica. The compute that represents it is the first fully ephemeral node. It serves as a bridge to object storage, streaming incoming writes. It serves no reads. Because it is a member of the quorum, a write is not acknowledged until it is durable in object storage. That adds a little latency to each write, but per-reference serialization keeps it from becoming a throughput bottleneck. The virtual write replica also coalesces transactions on disjoint references into a single 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. With the virtual write replica in place, GitHub can scale out as many virtual read replicas as a repository needs, on demand. 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. In internal testing, the distributed load testing harness routinely found ceilings in the current architecture. Against virtual read replicas, the harness hit its own limits first.

What comes next

The commit protocol that has taken GitHub to a billion repositories will not take it to the next billion and beyond. Every write still waits on replicas that each hold a full copy of the repository, yet very little of a write actually needs to be ordered. Git objects are immutable and named by their contents, so they can be stored without anyone agreeing on them. What is left is small, and the hard part is ordering it as fast as possible without moving the bottleneck somewhere else. Designing for that on a whiteboard is one thing. Doing it underneath a billion repositories that developers and agents are writing to around the clock is another. Getting there forced a rethink of second-order effects too, like where durable reference state lives and how compaction and garbage collection scale. Agent traffic is not slowing down, and each of these steps gives repositories more headroom as it lands, without waiting for the end state. The final post in this series will appear at GitHub Universe and will tour the end state, what it does for write throughput, the second-order problems that had to be solved, and why there is still a small consensus group somewhere in the stack.

The sources this article was written from

  • "GitHub Blog
    https://github.blog/engineering/architecture-optimization/the-bridge-to-agent-scale-git-infrastructure/"

Read next