Research explainer · XiaoHu Explains

How Cursor rebuilt Git hosting to tackle a 20-year-old problem: Inside the Continuity architecture

From Git's DAG and packfiles to GitHub Spokes, and then to Continuity with S3 WAL as the source of truth: a full walkthrough of why large-scale Git hosting is hard and how Cursor solves it.

One-minute overview
  • Vicent Martí has a long history with libgit2 and GitHub's Git infrastructure. This piece covers both the architectural evolution of large-scale Git hosting and the technical foundation for Cursor's Origin platform.
  • Git's DAG, packfiles, and strong consistency demands cause object databases, network filesystems, and fixed-replica architectures to hit walls as they scale.
  • Continuity uses S3 WAL as the source of truth and local Git as a hot cache, letting service replicas scale from zero with traffic. The 100, 120, and 300 figures are Cursor's own reported results; the full test conditions and reproducible data were not disclosed.

This post is from the official Cursor blog, written by Vicent Martí. It doesn't discuss editor features or model capabilities, but a more fundamental issue: why hosting Git at massive scale is extremely difficult, and why Cursor had to rebuild a Git storage system from scratch for its own code hosting platform.

Vicent Martí now works on systems at Cursor. Previously, he was at PlanetScale and GitHub. In 2010, he participated in libgit2 during Google Summer of Code. Later, on GitHub's systems team, he spent years dealing with clone, fetch, packfile, and large repository performance. In 2015, he documented how GitHub reduced the average CPU time for Git network operations by over 90% and contributed those optimizations back to upstream Git.

This background matters. This article is not a secondhand summary of Git architecture from an AI company. It is a first-party technical explanation from an engineer who has spent years working on Git's internals and hosting systems, written for Cursor's new platform.

In June 2026, Cursor announced Origin, its new Git platform, at the Compile conference. Two months later, this article provides the first systematic explanation of Continuity, the underlying storage system for Origin. The article thus carries two responsibilities: it reviews the pitfalls of Git hosting over the past two decades, and it makes the case that Cursor can evolve from a tool that helps users write code into infrastructure that preserves software history on their behalf.

The entire article can be condensed into a single sentence:

Continuity keeps native Git repositories on local NVMe, but makes the write-ahead log (WAL) in S3 the single source of truth. This turns the disk copy from critical data that must be carefully maintained into a hot cache that can be provisioned, destroyed, and rebuilt based on traffic.

The core problem: why hosting Git at scale is a nightmare

Git was designed for projects like the Linux kernel, which are highly decentralized and allow offline work. Every developer has a full repository, and the repository on the server uses essentially the same implementation as the repository on a developer's machine.

This makes small Git services easy to stand up: put an HTTP endpoint in front of a disk-backed repository, and you're running. But once you reach GitHub, GitLab, or enterprise code hosting scale, this "server is just a laptop" design creates three layers of trouble.

1. Git's underlying data is a graph

Git objects like commits, trees, and blobs reference each other by SHA, forming a directed acyclic graph (DAG).

To read a commit, the system must first fetch that commit to learn where its root tree and parent commits are. Only after getting the tree can it locate the addresses of the next level of files and subdirectories. The keys needed for the next step are hidden in the results of the previous step.

So storing each Git object separately in a distributed key-value database looks intuitively aligned with content addressing, but in practice it turns a local traversal into a large number of serialized network round trips. Many requests cannot be parallelized in advance because the next access target is unknown until the current step completes.

2. Packfiles add another layer of physical indirection

Git doesn't store every object in full. To save space, it packs many objects into packfiles and uses deltas to record the difference between one object and a base object. That base object may itself depend on another delta.

As a result, reconstructing a logical object requires Git not only to follow pointers through the DAG but also to jump across multiple physical locations within a multi-gigabyte packfile. Local NVMe keeps these random reads at very low latency, but once you cross a network filesystem, every jump incurs network cost again.

Source interaction · 01—02Git “jumps” once at the logical layer and again at the physical layer

Tip: pause autoplay, or use Previous / Next to step through each remote read.

Remote object traversalWhy an object database slows a history walk
Static SVG of the source page's Git DAG remote object read animation
Only the commit targeted by main is known1 / 6

The addresses of the next objects have not been exposed yet.

Random packfile readsWhy a delta still has to find its base
Static SVG of the source page's packfile random-read animation
Locate the target object1 / 6

The index only tells Git where the object sits in the packfile.

The source used two autoplaying SVG demos. Here, the original artwork remains, with play, pause, and step controls restored.

3. Git cannot tolerate casual eventual consistency

Many internet systems can accept data syncing a few seconds late. Git cannot.

A developer runs git push and it succeeds. The next second, git fetch cannot find the commit they just pushed. The client enters an anomalous state. A hundred CI runners clone simultaneously, and a few of them cannot read the commit they are supposed to test, producing random, hard-to-reproduce failures.

Large-scale Git hosting must satisfy three seemingly conflicting requirements at once: local Git operations must be fast, reads must scale horizontally, and all replicas must remain consistent with the published repository history.

Historical evolution: the traps predecessors fell into

One of the most valuable parts of the article is that it does not immediately declare how advanced Continuity is. Instead, it first reviews why several previous architectures failed. This is necessary to understand what Cursor's approach actually solves.

1. Distributed object storage: elegant storage, unbearably slow clones

The Google/JGit team tried putting Git objects into a distributed hash table (DHT). Normal operations could run, but the serial read cost of the DAG was high. More critically, no matter how the server stored objects internally, the Git client ultimately still required receiving a packfile over the network.

This meant the server had to traverse, filter, compress, and assemble the scattered objects into a pack. Shawn Pearce's later retrospective showed that a single clone of the linux-2.6 repository could take 15 to 30 minutes. The team eventually abandoned object-level DHT and retained native packs and indexes instead.

This failure demonstrates: Git objects being addressable by SHA does not mean that full Git workloads are suited to object-level remote access.

2. Distributed filesystems: retained Git, retained all its local assumptions

In its early days, GitHub tried NFS, GFS/GFS2, and DRBD, among other file-level or block-level replication schemes. The idea was pragmatic: keep the Rails app unchanged, keep the Git repositories unchanged, and just distribute the underlying filesystem.

The problem is that Git's default implementation makes heavy assumptions about local file locking, synchronization, atomic updates, and caching. Random reads from packfiles also split a single operation into many cross-network jumps. To avoid grinding to a halt, the entire packfile had to be cached locally as much as possible. But when a single filesystem needs to accommodate hundreds of thousands of repositories, this approach simply does not scale.

GitHub later retreated to a simpler approach: store ordinary Git repositories on local disks of dedicated file servers, and have Rails send operations via RPC to the machine holding the repository. This preserved native Git performance but still constrained each repository to a single machine.

3. Spokes: the first to preserve both performance and consistency

Around 2013, GitHub developed the system later known as Spokes. It established the basic shape of modern Git hosting:

  • Each replica is a native Git repository on NVMe;
  • Data is replicated at the packfile level, without rewriting Git's object model;
  • All critical replicas stay synchronously consistent, and reads can be served by any replica.

A push has two parts: the packfile saves new objects, and a reference transaction moves a branch to a new commit. Spokes can asynchronously fan out the larger pack to replicas, then use a three-phase commit (3PC) to coordinate the much smaller reference transaction. Only after a majority of nodes acknowledge does the reference actually commit, and only then does the push return success to the client.

Source interaction · 03—04Spokes: failures and tail latency enter the commit path

Tip: click a participant to toggle it; use the sliders for replicas and one-way latency.

3PC failure experiment5 / 5 online; ready to commit
Static SVG of the source page's three-phase commit interactive diagram
Spokes throughput simulatorMore replicas or latency means more waiting
Static SVG of the source page's Spokes push animation
SPOKES3PC phase coordination · one-way latency 20 ms

All 5 replicas enter coordination; more latency lengthens the commit cycle. This shows causality, not production throughput.

Fixed replicas consume space and add directly to synchronous commit latency.

Spokes ran for years not because it was "outdated," but because it correctly preserved local Git, packfiles, and strong consistency. Continuity did not overturn these choices either.

The real problem was that each critical replica in Spokes bore three responsibilities simultaneously:

  1. Serving clone, fetch, web UI, and API requests;
  2. Storing durable data that cannot be lost;
  3. Participating in write coordination for every push.

For popular monorepos, three replicas are not enough to serve CI traffic, but adding more replicas pulls more nodes into the 3PC, making pushes more likely to be held up by the slowest node. For the high volume of low-traffic, disposable small repositories created by agents, keeping three always-online replicas is severely wasteful.

The article's summary of Spokes is accurate: the lower bound on replica count is always too high, and the upper bound is always too low.

Moreover, the disk replicas themselves were the source of truth. The platform had to use an external routing table to record which machines held each repository, continuously check checksums, detect corruption, and repair it promptly. Every replica was like a pet that required careful attention — you could not just throw it away and rebuild it if it broke.

Cursor's solution: Continuity architecture

Continuity, which Cursor built for Origin, does not reject Git. Nor does it store commits, trees, and blobs directly as S3 objects.

It retains the most successful part of Spokes: regular Git repositories still run on local NVMe, and clone, fetch, reference transactions, and repack continue to use the mature Git toolchain. What actually changes is who gets to define the true state of a repository.

Architecture aspect Spokes Continuity
Source of truth Disk Git repositories on multiple critical nodes WAL in S3-compatible object storage
Role of local repository Service replica, durable replica, consensus participant Rebuildable high-performance hot cache
Write consistency Multi-replica 3PC coordinating reference transactions Local transaction preparation + S3 ETag conditional write
Routing External database records replica locations Rendezvous hashing computes preferred nodes
Read scaling Adding replicas also adds coordination cost Service replicas can be added or removed independently based on traffic

In Spokes, knowing where a repository lives means knowing which machines hold the critical replicas. In Continuity, a repository ultimately lives in the WAL; any healthy node can read the log and recover a local Git repository.

Rendezvous hashing still stably maps a given repository to a set of preferred nodes, improving cache hit rates and reducing write contention. But this mapping only affects performance, not correctness. Even if the node list is briefly inconsistent, the worst case is that another machine recovers the repository — not that two conflicting histories emerge.

What Continuity actually accomplishes is a separation of responsibilities:

  • The S3 WAL handles durability, complete operation ordering, and recovery basis;
  • The local Git repository handles high-speed execution of Git operations;
  • Replica count only matches current read traffic.

Key technical implementations in Continuity

1. WAL first: where a push officially takes effect

A write roughly goes through six steps:

  1. The frontend receives the client-uploaded packfile and reference transaction;
  2. The packfile is written to the local repository and simultaneously uploaded to S3 as an immutable WAL entry;
  3. The local Git prepares the reference transaction, validating old values and locking references, but does not commit yet;
  4. The frontend reads the WAL index and current ETag from S3;
  5. The frontend appends the pointer to the new entry to the index, writing it back conditionally with If-Match;
  6. Only after the index update succeeds does the local reference transaction commit, and only then does the server acknowledge the push.

Step five is the linearization point. Two frontends might upload WAL entries simultaneously, but if they both try to update the index with the same old ETag, only one succeeds. The loser receives 412 Precondition Failed, re-reads the latest index, places its write at the next position, and retries.

Source interaction · 05—06WAL writes and CAS races in time order

Tip: choose a phase or use play and step for the WAL push and CAS race.

One WAL pushLinearization happens at index CAS, not pack upload
Static SVG of the source page's Continuity WAL push animation
Receive push1 / 7

The frontend receives the packfile and builds its index.

Two frontends race on one ETagWAL entries do not conflict; index order has one winner
Static SVG of the source page's two-frontend CAS race
A and B upload WAL entries1 / 8

Different keys keep the immutable uploads from overwriting each other.

Static diagrams remain without JavaScript; JavaScript reveals each state and cause.

This effectively converges the write coordination that previously required multiple critical replicas into a compare-and-swap (CAS) on a single small WAL index object. Under healthy conditions, preferred nodes reduce contention. During failover, correctness is still determined by S3 conditional writes, not by relying on any single machine permanently serving as primary.

2. UDP gossip + ETag: messages can be lost, history cannot be stale

After a write completes, the primary node uses UDP gossip to notify other replicas to catch up on the WAL ahead of time. UDP can drop packets, reorder them, or even send notifications to nodes that no longer serve the repository. But it only optimizes performance; it never bears correctness.

Before a replica actually handles a fetch or clone, it first sends a conditional read to S3 using the ETag it has stored locally:

  • If S3 returns 304 Not Modified, the WAL index hasn't changed, the local copy is already up to date, and the replica can serve requests immediately;
  • If S3 returns 200 OK, a newer index exists, so the replica downloads it, replays any missing WAL entries, and then responds to the client.
Source interaction · 07Drop one gossip message to reveal the two read paths

Tip: toggle Drop UDP gossip and step through the sequence to compare the 304 fast path with the 200 catch-up path.

Replication and read correctness
Static SVG of the source page's gossip and conditional-read replication diagram
Client pushes to the primary1 / 7

The primary first commits the new WAL entry and index to S3.

Current path: gossip arrives and the replica catches up early; the fetch-time conditional GET returns 304.

The switch changes only the performance path, not correctness: both paths must confirm the latest index before returning data to the client.

The post reports that these 304 checks, which only touch S3 metadata, average under 10 milliseconds. That's Cursor's own production observation, not a general latency guarantee from AWS across all regions and workloads.

3. Elastic replicas: from zero to hundreds, scaling with traffic

Once the WAL becomes the source of truth, the local repository effectively turns into a cache.

  • Popular monorepos can scale to dozens or even hundreds of service replicas, spreading the load across clone, fetch, Web UI, REST API, and Agent RPC traffic;
  • Ordinary repositories might only need one local replica;
  • Repositories that see no traffic for a long time can be reclaimed from node disks, dropping their local replica count to zero. The next time someone accesses them, the replica is rebuilt from the WAL.

In this context, "zero replicas" means zero local service caches, not that the repository data has disappeared. The post does not claim that every repository can be restored "in seconds," so rebuild speed should not be presented as a universal guarantee.

4. Single-node repacking: trading bandwidth for duplicated CPU work

Every push generates a new packfile. As packfiles accumulate, even a fast single index query becomes a problem when repeated hundreds or thousands of times, so repositories still need periodic repacking.

In Spokes, multiple key replicas may redundantly perform expensive CPU-bound compression. Continuity instead assigns repacking only to the current primary node, which applies the compression result to both its local repository and the WAL. Other replicas skip the recomputation entirely and simply download the already-compressed pack from S3, trading network bandwidth for duplicated CPU work.

Source interaction · 08—09Local replicas come and go as WAL compaction advances

Tip: play traffic changes, or add packs and trigger compaction to move the frontier.

Replicas scale with trafficHot monorepo: 6 replicas; cold repo: 0—1
Static SVG of the source page's repo heat and elastic replica diagram

Dashed slots are reclaimed caches; authoritative state remains in the S3 WAL.

Incremental WAL compaction3 packs; below compaction threshold
Static SVG of the source page's WAL incremental compaction diagram
basea1b7
COMPACTION FRONTIER
#97 base.wal
#98 a1.wal
#99 b7.wal

Each change updates the WAL index first; at the threshold, the primary merges small packs into a larger one.

“0 replicas” means no resident cache—not lost data or guaranteed instant recovery.

5. The WAL's other value: full provenance and recovery

Production Git repositories can suffer from static data corruption, repack bugs, push race conditions, and edge-case errors in Git itself. Continuity writes every push and repack event into the WAL, which means it can track every underlying state a repository has passed through.

Replicas can move forward to the latest state or roll back to a point before an error occurred. Engineers can pinpoint which push or repack introduced the problem and then rebuild the repository from the operation log.

This is also a key difference between Continuity and architectures that put packfiles in object storage and refs in a relational database: Continuity tries to use a single log to capture persistence order, ref changes, and recovery history, avoiding two authoritative states that must stay in sync.

5. Performance numbers, and what they don't prove

Cursor shared three headline results from internal testing:

  • In a synthetic stress test with up to 100 replicas, read throughput scaled roughly linearly with replica count, with no obvious regression in push throughput;
  • With S3 Standard, the cluster sustained roughly 120 pushes per second while also completing compression and result replication;
  • With the lower-latency S3 Express One Zone, throughput exceeded 300 pushes per second, and the bottleneck shifted to local Git compression.
Source static charts · 10—11Only the final two visuals are static performance charts

The first nine are SVG animations or interactive components; these two are the ones suited to direct static placement.

Clone throughput scales nearly linearly as read-only replicas are added

Reads: near-linear scaling up to 100 replicas

This supports the narrow claim that read capacity can scale by adding replicas; it does not mean every workload scales perfectly linearly.

Push throughput test for S3 Standard and Express One Zone

Writes: Standard peaks at 120 push/s; Express exceeds 300

Object-store latency clearly affects the write ceiling, showing that the authoritative log layer still constrains write performance.

Evidence boundary: The source does not fully disclose test hardware, object distribution, request mix, P95/P99, fault injection, or long-term production SLOs. These are Cursor's self-reported results, not an industry-wide guarantee.

Media accounting corrected: nine interactive demos plus two static charts.

These numbers support a specific conclusion: once the source of truth moves out of the replica cluster, adding read replicas no longer necessarily adds coordination overhead to every push. The read-write decoupling direction in Continuity has internal testing behind it.

But they do not directly prove that Origin has reached GitHub-level long-term production reliability. The post does not disclose complete hardware specs, repository object distribution, push sizes, request mixes, P95/P99 latencies, fault injection results, cross-region disaster recovery, long-term SLOs, or reproducible experimental data. The primary test subject is Cursor's own monorepo, everysphere.

So "near-linear read scaling" is more accurate than "perfectly linear scaling," and "idle repositories can be rebuilt from the WAL" is more accurate than "the next access will always restore in seconds."

Zooming back out to the product layer, Continuity is the technical foundation for Cursor's Origin code hosting platform. Cursor's bet is that agents will generate more code, PRs, CI runs, and throwaway repositories, turning version control from a tool developers occasionally touch into a coordination layer that large numbers of automated systems continuously contend for.

What this post really shows is not just that Cursor built a faster Git backend — it's that Cursor is expanding its own responsibility: from helping developers generate code to preserving software history for them.

The architecture is well explained, and the internal data suggests the direction is viable. But code hosting ultimately isn't won by a polished engineering post. It's won years later, when every ordinary, boring, uneventful push can still be fully recovered.

Source
Git at any scaleVicent Martí·2026-08-18·View primary source
Site note
Continuity's 100 replicas and 120/300 pushes per second come from Cursor's own synthetic tests; there's no full test environment or reproducible data.