← Go back
System Architecture

How Google Drive Syncs Files and Resolves Concurrent Edits

Trace the mechanisms behind reliable file sync: incremental uploads, version checks, and conflict copies that preserve both edits.

Advanced·

High-level overview: why one upload becomes a distributed systems problem

To a user, a cloud drive is folders and files. Behind it are two systems: a metadata system for names, folders, permissions, versions, and sync positions; and a byte system for large, slow-to-copy file objects. Combining them in one database or request path makes both a bottleneck.

Several devices and collaborators make failures normal: transfers interrupt, devices edit offline, and regions fail. A safe design turns each into a retry or recoverable conflict. It needs one authoritative result for metadata changes, resumable byte transfer, and a durable history for devices that were offline longer than a folder listing can explain.

Durability is more than replicas: checksums detect corruption, independent copies survive hardware loss, history and delayed deletion recover from mistakes, and restore drills validate the whole chain. Each covers a different failure.

Scope and assumptions

The design covers files, folders, sharing, history, resumable transfer, multi-device sync, and machine, zone, and regional failure recovery. Authentication, search, media processing, antivirus, billing, legal retention, and live Google Docs-style editing are out of scope. “No data loss” means an acknowledged version survives the failures designed for.

Functional requirements

  1. A client can create a folder and upload, download, rename, move, trash, restore, or permanently delete a file.
  2. An interrupted upload resumes without retransmitting confirmed chunks.
  3. A committed file version downloads byte-for-byte identically to the uploaded input.
  4. A user can list prior versions and restore one as the current version.
  5. Owners can grant and revoke viewer or editor access to users and groups.
  6. Each device can request all changes after its last cursor without rescanning the full tree.
  7. Desktop and mobile clients detect local changes, queue them offline, and resume sync after reconnecting.
  8. The service stores any binary file type and enforces configurable account, version, and retention limits.

Non-functional requirements

PropertyDesign target
Metadata latencyp99 below 150 ms in the user’s home region, assuming nearby regions
Transfer setup latencyp99 below 300 ms; byte transfer remains network-bound
ConsistencyStrictly serializable metadata mutations within a drive shard; eventual notification delivery
Durability99.999999999% annual object durability target; acknowledge a version only after its bytes and metadata are durable in another region inside the same residency boundary
Scale1 billion accounts, 100 million daily active users, 102,000 peak metadata QPS
CostAt most 0.81 stored bytes per logical byte before replication, assuming 30% data reduction and 15% storage overhead
Transport securityTLS 1.3 externally and mutual TLS between internal services
Storage securityAES-256 at rest with envelope encryption; key rotation within 90 days
AuditPermission changes and file access enter an append-only log within 5 seconds

Strict serializability combines serializable multi-record transactions with linearizable real-time ordering: if commit A finishes before commit B begins, B observes A. If replicas cannot safely agree, the system delays or rejects the write rather than claim an order it cannot keep.

Back-of-the-envelope estimation

Assume 1 billion registered accounts, 100 million daily active users (DAU), 20 metadata reads, two file-version commits, and ten downloads per active user per day. The metadata-read count includes listing, permission, and download-setup calls. Assume an 8 MiB average upload, a 4 MiB average download, a four-times peak factor, 30% savings from compression and deduplication, three replicas, and 15% storage overhead.

FigureVisible arithmeticResult
Metadata reads100M × 20 ÷ 86,40023,148 average QPS
File-version commits100M × 2 ÷ 86,4002,315 average QPS
Read-to-file-commit ratio20 ÷ 210:1
Peak metadata load(23,148 + 2,315) × 4101,852 QPS
New logical bytes100M × 2 × 8 MiB1.49 PiB/day
Yearly logical growth1.49 PiB × 365544 PiB/year
Physical yearly growth544 PiB × 0.70 × 3 × 1.151,314 PiB/year
Average ingress1.49 PiB × 8 ÷ 86,400155 Gbit/s
Average egress100M × 10 × 4 MiB × 8 ÷ 86,400388 Gbit/s
Peak edge bandwidth(155 + 388) Gbit/s × 42.17 Tbit/s
API nodes101,852 ÷ 2,000 QPS/node × 2102 nodes with redundancy
Storage nodes for one year1,314 PiB × 1,024 ÷ 20 TiB/node × 1.25about 84,100 nodes

The per-node figures are planning assumptions. Real benchmarking decides the final count. The calculation exposes the governing fact: storage fleet size and repair traffic dominate the API tier.

Choosing the upload path

There are three common ways to move file bytes. Only one keeps the application tier out of the expensive data path.

ApproachHow it worksBenefitCost
Store on the API serverClient uploads to local server diskMinimal prototypeServer loss can lose data; disk and scaling limits arrive quickly
Proxy through the API serverServer forwards the body to the chunk storeCentral policy enforcementEvery byte crosses the application fleet twice
Direct uploadMetadata service issues limited-time URLs; client writes through the chunk-store gatewayLowest server bandwidth and independent transfer scalingRequires secure tokens, commit validation, and abandoned-upload cleanup

Choose direct upload as the default. Small files may use a separately scaled ingest pool; larger or unreliable transfers use a resumable session and go directly to the chunk store. The chunk store has a flat key space, so folders live in metadata and renames never move bytes.

The chunk-store gateway verifies the authorized length and cryptographic digest against the received bytes before issuing a durable receipt; it never trusts a client-declared chunk ID alone.

Core concepts

Follow one file from a laptop to another device: split it, store its pieces, publish their manifest atomically, reject accidental overwrites, and let other devices replay the durable change.

1. Split a file into chunks

Restarting a 5 TB upload after one timeout is unacceptable. Re-uploading an entire virtual-machine image after a small edit is wasteful. Chunk boundaries decide how much work a retry or edit creates.

A chunk is an immutable piece of a file. A manifest records its ordered chunk references, sizes, checksum algorithm/version, whole-file checksum, and encryption metadata, so it can rebuild one exact version. Edits create new chunks only where bytes change; failed-upload chunks remain invisible until later cleanup proves no retained manifest needs them.

2. Keep file details separate from file bytes

The metadata service handles names, folders, owners, access rules, versions, and sync positions. The chunk store holds immutable file chunks, and its chunk-store gateway verifies direct uploads and downloads. A client asks the metadata service for a temporary URL, then sends bytes directly to the chunk-store gateway.

This keeps large file traffic away from API servers. The temporary URL works only for one upload session or file version, expires quickly, and cannot be used for another file.

3. Choose where chunks begin

A SHA-256 hash identifies a chunk’s plaintext bytes, but is not its storage identity. A reusable chunk is identified by (dedupeScopeId, hash, byteLength, encryptionDomain): the scope limits reuse to one tenant or trusted organization, and the encryption domain prevents references across incompatible keys.

Fixed-size chunking cuts every N bytes. It is simple and predictable. Content-defined chunking (CDC) uses the file’s contents to choose boundaries. After a small insertion, later boundaries can line up again, so more old chunks can be reused. CDC costs more CPU and produces variable-sized chunks; it is useful for large files that change often, not required for every upload.

4. Make a complete version visible

Uploading chunks does not make a file visible. The publish transaction verifies durable receipts, saves the manifest, changes currentVersionId, and records the sync event. Readers see the old complete file or the new one, never a partial file.

5. Stop one device from overwriting another

Each update includes the version the client started from, often as an ETag (an opaque version token) or version number. The server accepts the update only when that version is still current. If another device changed the file first, the server reports a conflict instead of silently overwriting newer bytes.

6. Help every device catch up

A notification is a doorbell, not a history book. It tells a device to check for changes, but it can arrive late or more than once. The change feed is the saved, ordered history. Each device stores a cursor per drive, meaning “I have applied everything up to here.” It saves the next cursor only after it has safely applied those changes locally.

Quick path: the model to remember

With the core concepts in place, newer system-design readers can next read the Write path and Handle offline edits and conflicts; the estimates and deep dives are optional on a first pass.

  1. Keep names, permissions, and version pointers in the metadata service; keep large bytes in immutable chunks.
  2. Upload chunks directly, then publish one manifest in a metadata transaction. Until that commit, no reader sees the new file.
  3. Treat notifications as a wake-up signal. The durable change feed, replayed from a saved cursor, is what keeps devices correct.
  4. Send the base version with every edit. A stale binary edit becomes a conflict copy rather than overwriting work.
  5. Delete cautiously: retained manifests are the source of truth for garbage collection.

Detailed design

Components and ownership

The architecture separates two jobs: moving bytes and deciding which version users should see. The most important step is the single metadata commit between those jobs.

System components and ownership System components and ownershipSystem components and ownership
  • The gateway authenticates metadata requests; the token service grants limited file-data access.
  • The transactional store owns file names, current versions, permissions, upload sessions, group-membership versions, and change history. A consensus quorum orders its changes; an acknowledged version also requires durable chunk copies in at least two regions. If either guarantee cannot be met, the service rejects the write.
  • The chunk store owns chunks that never change. It keeps the required copies in separate zones, including another region inside the same residency boundary before it confirms a write. A background job later moves old versions to cheaper storage without changing their manifests.
  • Notification fanout consumes the committed metadata change log through its transactional outbox. Devices recover missed signals from the change log.

The metadata service groups records by driveId. This keeps most operations for one personal drive or shared workspace on the same database shard. As a result, ordering changes and running transactions is simpler.

The transaction and ordering guarantees hold within one drive shard: moves, cycle prevention, placement, ACL inheritance, and optional name uniqueness are strictly serializable multi-record operations. Cross-drive moves and quota changes for another owner need a distributed transaction or reserve/confirm step and are out of scope.

A very large shared drive can split folder listings and event storage, while a compact per-drive sequencer—the logical writer that assigns the next cursor only when a metadata transaction commits—assigns one ordered changeCursor to each committed change. Clients retain that one cursor; event partitions are an implementation detail behind it. This single strict drive cursor is a deliberate teaching simplification: on a huge shared drive it becomes a hot writer. The scale-out path partitions the feed and uses snapshot watermarks plus composite partition cursors; file operations still serialize at their owning shard. Stable IDs are storage keys; paths are metadata.

The cache stores file summaries, folder pages, and permission results. Every cached result includes the version it came from. Effective ACLs may be cached or materialized with the relevant ancestor-ACL and group-membership versions; authorization validates those versions before granting access. Revocations advance or invalidate those versions, and a previously minted download URL can remain useful only until its short expiry.

Final logical quota is checked atomically at commit, not per chunk, because transfers can be abandoned or deduplicated. To prevent rejected uploads from consuming unlimited resources, session creation also enforces per-tenant byte/session limits and can reserve quota for large files. A background job calculates physical storage after deduplication.

Each metadata shard has one chosen write leader and several copies, including the remote copy required for durability. If the leader fails, the copies choose a new one. This gives versions and permissions one clear order without relying on one machine. If too few copies can agree, the system rejects writes instead of claiming they are safe.

API surface

Start with the large-file path: create a session, upload each chunk, then commit. The other rows manage folders, downloads, syncing, and sharing. Every metadata-service call uses TLS, authentication, and authorization. A mutation includes an idempotency key, a client-supplied retry token that returns the original result instead of creating a duplicate.

Important failures are explicit: stale base versions return 409 Conflict, expired upload sessions or sync cursors require a new session or snapshot, invalid manifests/checksums are rejected, and throttled clients back off.

GoalURL or URL sequenceInputOutput
Create, rename, move, or trash a file or folderPOST /v1/items or PATCH /v1/items/{itemId}Create: { parentId, name, kind }. Update: { baseMetadataVersion, name?, parentId?, trashed? }.{ itemId, metadataVersion, createdAt } or { itemId, metadataVersion, changeCursor }. A stale metadata version or a move that creates a loop is rejected.
Upload a small file in one requestPOST /v1/files/{fileId}/contentRaw file bytes. Headers include Content-Type, X-Base-Version-Id, X-File-Checksum, and Idempotency-Key.{ fileId, versionId, version } — the new file version.
Upload a large file in resumable chunks1. POST /v1/files/{fileId}/upload-sessions 2. POST /v1/upload-sessions/{sessionId}/chunks 3. PUT {transferUrl}1. File size, type, base version, checksum, and chunking mode. 2. Chunk number, length, and checksum. 3. Chunk bytes.1. { sessionId, chunkingProfile, expiresAt }. 2. { transferUrl, expiresAt }. 3. { chunkId, receivedBytes }. The client can retry a chunk safely.
Find already stored chunksPOST /v1/upload-sessions/{sessionId}/chunks:check{ chunks[] }, with chunk IDs and lengths{ present[{ chunkId, leaseReceipt }], missing[] }
Resume an uploadGET /v1/upload-sessions/{sessionId}Session ID{ state, receivedChunks[], expiresAt }
Make the uploaded file visiblePOST /v1/upload-sessions/{sessionId}/commit{ chunks[], fileChecksum }, with chunk IDs and lengths in order.{ fileId, versionId, version, changeCursor }. The service checks every chunk before publishing the version; a stale base returns 409 Conflict.
Create a conflict copyPOST /v1/upload-sessions/{sessionId}/conflict-copyparent and a client-chosen conflict nameThe client explicitly commits the retained stale upload as a sibling item.
Download a fileGET /v1/files/{fileId}/download?version={versionId}fileId; optional versionId.{ manifest, transferUrls[], expiresAt }. The client downloads the chunks, rebuilds the file, and checks its checksum.
Catch up after being offlineGET /v1/drives/{driveId}/changes?cursor={cursor}&limit={n}Drive ID, saved cursor, and optional page size.{ changes[], nextCursor, hasMore }. Save nextCursor only after applying the changes locally.
Share a file or folderPUT /v1/items/{itemId}/permissions/{principalId}{ role, baseAclVersion }, where the role is viewer, commenter, editor, or owner.{ aclVersion, changeCursor }. An access-control list (ACL) version refreshes permission caches.

baseVersionId, baseMetadataVersion, and baseAclVersion are safety checks for file contents, file details, and permissions. The server accepts a change only when the relevant value has not changed since the client read it. changeCursor is a private saved position in the change history, not a clock time.

A lease receipt is a short-lived, signed proof that one upload session may reference one verified chunk under stated size and durability constraints. The batch check returns a lease receipt for each reusable chunk, and commit accepts it only while that receipt remains valid. Garbage collection deletes a chunk only when it is unreferenced by retained manifests and has no valid upload lease.

Data model

RecordImportant fieldsInvariant
UseruserId, subscription tier, home region, logicalQuotaBytes, usedLogicalBytesOne user owns the quota for personal files
DevicedeviceId, userId, platform, lastAppliedCursorByDrive, lastSeenAtEach drive cursor moves forward only after local changes are saved
WorkspacedriveId, ownerId, sharing mode, home regionDefines who shares data and where its updates are ordered
ItemitemId, driveId, parentId, name, file type, sizeBytes, owner, creator, timestamps, currentVersionId, metadataVersion, aclIdStable ID and parent define placement; duplicate names are a product policy
FileVersionversionId, fileId, manifestId, baseVersionId, sizeBytes, file checksum, creatorNever changes after commit
ManifestmanifestId, ordered chunk references, total bytes, file checksumRebuilds one exact file
ChunkdedupeScopeId, SHA-256 hash, byte length, encryption domain, key reference, copy statusThe scoped tuple, not hash alone, identifies immutable bytes
UploadSessionsessionId, expected file details, received chunks, expiry, statePublishes at most once
PermissionaclId, user or group, role, inherited-from field, aclVersionRemoving access changes its version in one step
GroupMembershipgroupId, principal, membershipVersionAuthorization evaluates current membership, not a stale ACL cache
Changefeed position, item, operation, resulting versionSaved in order and safe to replay

The subscription tier is the user’s plan, such as free or business. Logical quota is the amount of file data the user is allowed to store, counted by file size—not by how many internal copies the service keeps. usedLogicalBytes is how much of that allowance is currently used.

Client-side sync engine

The client needs a watcher, local database, indexer, chunker, and durable transfer queue. It uses operating-system events for efficiency, but treats them as hints.

Local changes and remote updates Local changes and remote updatesLocal changes and remote updates
  • Debouncing combines repeated auto-save events before expensive chunking begins.
  • The local index stores file identity, versions, hashes, and queued work across restarts.
  • A durable queue retries uploads, while the change feed supplies edits from other devices.

The local-change algorithm debounces rapid events until size and modification time settle, compares stable file identity and metadata with the local index, then classifies create, content update, rename, move, or delete. For a content update it records chunk work and the future metadata commit in a durable queue before network work begins. After commit it saves the new base version, continues from its old cursor, and safely skips its echoed change. At startup, watcher overflow, or suspected loss, it reconciles only the affected area against the local index.

PlatformChange mechanismRecovery concern
WindowsUSN Journal with ReadDirectoryChangesW as a live hintThe journal supports durable recovery; the live API can overflow and needs a targeted rescan
macOSFSEventsRescan a changed subtree
Linux/Androidinotify / FileObserverWatch limits and suspended-app wake-up
iOS/iPadOSFile Provider / NSFilePresenterSandbox and background limits

The client limits parallel chunks, reduces concurrency on weak links, resumes confirmed ranges, and reuses connections. Compression is conditional and layer-specific: Gzip/Brotli applies to client-to-gateway transfer of compressible text; Zstandard/Snappy applies to speed-sensitive internal replication or metadata storage; LZMA applies only to cold internal archives. Skip recompression for already-compressed or encrypted bytes.

Names need platform-independent rules too. The metadata service canonicalizes Unicode names to NFC, while macOS clients tolerate filesystem-provided NFD and compare the canonical form. Windows-style case-insensitive folders reject names that collide after case folding. Finally, many editors save by writing a temporary sibling and then renaming it over the original; debouncing plus stable file identity lets the client treat that sequence as one replacement instead of syncing a transient file.

Write path

The write flow waits to publish the file until its chunks and metadata are durable. A storage event alone never changes the current file version.

A safe write flow A safe write flowA safe write flow
  • Chunk retries are safe because their identities and checksums remain stable.
  • The commit validates durable receipts before changing the visible version pointer.
  • Change fanout starts from the committed log entry, never from a chunk-store callback.

The client hashes chunks and the whole file, batch-checks eligible chunks, uploads only misses in parallel, and retries safely. The chunk-store gateway verifies each received digest and length before confirming the required copies across separate zones and the remote region. Commit checks ordered chunk receipts, quota, and the base version. Success requires both a metadata consensus quorum to order the transaction and receipts proving full-data chunks in at least two regions; consensus alone is not a cross-region byte-durability acknowledgement. The transaction then saves the manifest, advances the current-version pointer, and writes the change record before success returns. Notifications are later, never part of commit.

An upload starts as pending. While the service checks and publishes it, it is committing. After the database transaction succeeds, it is committed. A session that waits too long becomes expired.

The idempotency key identifies one upload attempt. If the client retries the same request, the service returns the existing session or its saved result instead of starting another upload. Only one commit can publish the manifest. If a worker fails before the database transaction, a retry can safely finish the work. If it fails after the transaction, a retry returns the committed version. A timeout therefore never creates two versions or leaves the client guessing what happened.

Direct upload does not give the client general access to storage. Each temporary URL allows one operation on one expected chunk or byte range. It limits the size, checksum, account, and expiry time. For CDC, the client gets the next URL only after it knows that chunk’s boundary. Storage rejects anything outside those rules, so a stolen URL cannot read arbitrary files or write unrelated objects.

Read and sync paths

For a download, the service checks permission and loads the requested Item and FileVersion. It reads the manifest and returns short-lived chunk URLs. The client downloads chunks in parallel, verifies each hash, rebuilds the file, and checks the whole-file checksum. If one replica returns bad bytes, storage tries another copy and schedules a repair.

The server can stream small files through an edge cache, but large downloads should remain direct. Range requests map byte offsets to manifest entries, allowing video seeking or partial recovery without assembling the whole file in a server. Popular public files need a separate abuse and content-delivery policy so one shared link cannot exhaust the owner’s metadata shard. The authorization decision can mint a cacheable signed response while the bytes come from a content delivery network.

For sync, push or a long-held connection wakes the client; it applies GET /drives/{driveId}/changes pages in cursor order, then persists the new cursor. If retention has expired, the server chooses one history position, returns a snapshot valid at that position, and returns the exact cursor from which replay resumes. Without that shared boundary, a change made during snapshot transfer could be missing from both the snapshot and the later feed. Clients can safely replay already-applied changes, but must never advance their cursor past unapplied changes.

Per-drive cursors cannot discover a drive that was newly shared with a user. A separate per-user access feed records drive grants, revocations, and individually shared items. On a grant, the client creates that drive’s first cursor and syncs it; on a revocation, it removes local access. Long polling suits one-way hints, WebSockets suit frequent two-way messages, and mobile push saves battery—but every option falls back to periodic feed polling.

Sharing, security, and cache policy

Every metadata read and download authorization evaluates the ACL, its ancestor versions, and current group membership. Permissions can target users, groups, domains, or links; roles are viewer, commenter, editor, and owner. Children inherit folder ACLs unless overridden. Moves are therefore security operations: caches include ACL and membership versions, and any minted URL lasts only until short expiry. Permission and membership changes enter the audit log.

Security layerDesign
External transportTLS 1.3
Internal transportMutual TLS with short-lived service identities
File chunks and metadataAES-256 envelope encryption with keys in a managed key service
Enterprise keysOptional customer-managed encryption key reference per workspace
AuditAppend-only records for reads, writes, sharing changes, deletes, and restores

Caching follows the cost of being stale rather than one universal rule.

Cached dataFreshness policyReason
Metadata and ACLsVersioned entries; compute ACLs from ancestors at authorization timeCached transfer authorization can remain stale only for the short-lived URL
Thumbnails and previews30–60 second time to liveRegeneration is expensive, while brief visual staleness is acceptable
Client sync stateEvent-driven invalidation plus cursor pollingPush gives speed; the durable feed prevents missed changes

Versions, quota, and retention

Every committed edit creates an immutable FileVersion; restoring one creates a new current version pointing to its manifest. Retain the newest 100 versions or 30 days, whichever preserves more, plus explicitly pinned versions. Retained versions count toward the owner’s logical quota, never viewers’ accounts or deduplicated physical usage. These are product policies, not Google measurements.

Deep dive: three hard sub-problems

1. Publishing bytes without partial files or acknowledged loss

The dangerous gap sits between storing bytes and changing metadata. If metadata points to missing chunks, the file is corrupt. If chunks exist but metadata commit fails, capacity leaks but user data remains safe. The design must prefer the second outcome.

CandidateStrengthCost or failure mode
Write bytes through one database transactionSimple conceptual commitDatabases are poor large-blob transfer engines; locks and logs become enormous
Upload mutable object, then rename itFamiliar file-system modelObject stores do not generally provide a cross-system atomic rename with metadata
Immutable chunks plus transactional manifest publishReaders see one complete version; retries are safeRequires orphan collection, reference accounting, and two storage systems

Choose immutable chunks and publish a manifest only after receipts prove the required durable copies. The transaction checks receipts, saves the manifest, advances the version pointer, and writes the change record. Failed sessions leave only invisible data for later cleanup.

Garbage collection uses two passes: mark from retained manifests and quarantine apparent orphans; then, after the longest replication and backup delay, recheck references and upload leases before deletion. A counter alone is unsafe after missed events or a restored backup. Background scrubbing verifies hashes, repairs bad copies, and periodically rebuilds sample files from independent replicas to compare their whole-file checksums. Track detected damage, successful repairs, unrecoverable objects, and the age of the last successful check separately. Acknowledge only after the required zone copies, remote regional copy, and metadata transaction are durable; this deliberately adds write latency. The versioned whole-file checksum catches valid-but-misordered, duplicated, or missing chunks.

2. Chunking strategies: moving only the bytes that changed

CandidateStrengthCost or failure mode
Whole-file uploadFew requests and minimal client CPUTerrible retry cost; no delta transfer
Fixed 4–16 MiB chunksPredictable memory, parallelism, and offsetsInsertion near the front shifts later chunks
Content-defined chunks with min/target/max sizesPreserves boundaries around insertions; better deduplicationMore CPU, variable parts, and abuse controls needed

Fixed-size chunking uses predictable 4–16 MiB offsets: boundary choice is O(1), though hashing the file remains O(n). It supports parallel upload and range reads, but an early insertion shifts later chunks. CDC cuts when a rolling fingerprint matches a mask, so boundaries usually realign after an insertion; it suits frequently edited VM images, snapshots, and similar binaries.

Use fixed chunks for videos, encrypted archives, and other low-reuse formats; use CDC for large, frequently edited files. Minimum/target/maximum sizes prevent tiny-chunk abuse. A Rabin fingerprint can find boundaries in O(1) work per window, but SHA-256 identifies the final chunk. Version and constrain server-approved chunking profiles in the manifest so upgrades cannot break resume or trigger millions of lookups.

for each byte window:
    rolling_hash = remove(old_byte) + add(new_byte)
    if chunk_size >= minimum and rolling_hash & mask == 0:
        cut chunk
    if chunk_size == maximum:
        force cut

The manifest records which chunking algorithm and settings were used. Without that information, a client upgrade might split the same file differently and break upload resume or deduplication. The server should support a few versioned profiles instead of accepting any client-supplied setting. It can reject an unreasonable manifest before performing millions of chunk lookups.

The upload decision stays observable and deterministic. This flow avoids pretending that one chunker fits every format.

Choosing a chunking strategy Choosing a chunking strategyChoosing a chunking strategy
  • Small files avoid multipart overhead, but a failed one-request upload starts over.
  • Fixed chunks favor predictable throughput; content-defined chunks favor reuse after edits.
  • Every path converges on cryptographic hashing and upload of only missing chunks.

Compress before encryption only when sampling predicts a benefit; JPEG, MP4, ZIP, and many office files are already compressed. Deduplicate only inside an allowed tenant boundary and encryption domain, using the scoped chunk identity defined above. With server-side encryption, the service can deduplicate validated plaintext references before storing one encrypted representation. Randomized ciphertext cannot itself deduplicate; convergent encryption can, but creates confirmation-of-file risks. End-to-end-encrypted clients therefore normally forgo server-side deduplication. Never expose cross-tenant chunk existence through timing, quota, billing, or a client-visible lookup.

3. Handle offline edits and conflicts

An offline device must replay missed changes and never silently erase its own edit. The same transaction that changes metadata writes the ordered feed entry; notifications only prompt a read. A client persists its cursor only after applying a page, and cursor_expired triggers a snapshot plus fresh cursor.

Edits carry their base version. A match commits; a mismatch returns 409 Conflict with the current version and leaves the upload session available. The client fetches the current content, merges when it can, or explicitly creates a sibling conflict copy from the retained session; the server never silently creates one. Timestamps are display data, not ordering. A single ordered metadata writer does not need version vectors for server-side ordering, though version vectors can still help client-side causality or conflict diagnosis. For structured text, merge only with domain-aware rules; collaborative documents use OT/CRDT rather than attempting to merge arbitrary ZIP, image, or video bytes.

Offline edit and conflict flow Offline edit and conflict flowOffline edit and conflict flow
  • A matching base version takes the normal commit path.
  • A collaborative document goes to its collaboration service.
  • A binary conflict or delete-versus-edit race keeps recoverable content instead of discarding bytes.

For binary files, the first accepted edit keeps the original name. After 409 Conflict, the client can explicitly commit the retained stale upload as a sibling item, for example Design (Asha's conflicted copy 2026-09-20).pptx, linked to its original item for cleanup and user-visible resolution. Renames, moves, edits, and deletes use separate version checks because they change different parts of a file’s record. A delete becomes a temporary marker, called a tombstone, so an offline edit can still be recovered.

Concurrent operationsPolicy
Content edit and content editThe first successful edit stays primary; the stale commit returns 409; the client can create a conflict copy
Rename and content editCheck the rename and the content edit separately. Apply both when both checks pass; reject only the stale change
Delete and content editKeep a tombstone for the delete. Return 409; the client can preserve its stale bytes as recoverable conflicted content instead of silently restoring the file
Folder move and child updateCheck the folder move and child update separately. Apply both when valid; reject only an invalid destination or a cycle
Two folder movesThe first move chooses the parent; return a conflict for the later stale move

Moving a folder changes the visible path of every file below it. Rewriting every child record would be slow and risky. Instead, store stable parent IDs, reject moves that create a cycle, and write one subtree-move event. New clients can understand that event directly. A compatibility worker can expand it into individual changes for older clients.

Full high-level design

Now that the client sync engine, chunking, safe publication, and conflict handling are established, this end-to-end view connects them to the metadata authority. Solid paths carry synchronous requests; the dashed notification is only a wake-up signal, so every client still catches up from the durable change feed.

Full high-level design Full high-level designFull high-level design
The metadata service is the publish authority; storage holds immutable bytes; notifications accelerate but never replace change-feed replay.

Bottlenecks and failure modes

SituationWhat breaks firstMitigation
Normal growthHot metadata partitions for huge shared folders or celebrity linksHash-shard memberships, paginate stable snapshots, and isolate download authorization from listing
Upload burstSession creation, token signing, and chunk-store ingress saturatePreallocate upload-session capacity, rate-limit per tenant, apply backpressure, and let clients use exponential retry
Notification outageConnected devices stop learning about changes quicklyClients poll the durable feed with jitter; rebuild fanout from retained log positions
Metadata cache serves stale ACLRevoked users could retain apparent accessCompute ACLs from ancestors at authorization time; any already minted transfer URL remains usable only until its short expiry
Zone loss during uploadSome chunk writes lose replicas or stallQuorum across zones, retry another endpoint, and refuse commit until every receipt meets durability policy
Region isolationStrong cross-region metadata writes may stopRoute home-region traffic to a surviving quorum or enter read-only mode; never accept unreplicated writes as durable
Silent corruptionA replica returns incorrect bytesEnd-to-end checksums, background scrubbing, alternate-replica reads, and automatic repair
Ten-times trafficMetadata leaders, change partitions, repair bandwidth, and storage fleet all face nonlinear pressureSplit by drive, separate foreground and repair budgets, add regions, and move cold versions to erasure-coded tiers

Treat garbage collection as a data-loss risk: mark from committed manifests, quarantine apparent orphans, wait through replication and backup delay, then recheck before deletion. Uneven traffic hurts first—large workspaces, popular files, and retry storms need tenant limits and separate user, repair, and cleanup pools. At 10× load, shard metadata and feeds, add storage/regions, and reserve disk and network for repair. During an outage, degrade features rather than guarantees: serve safe reads without metadata majority, limit commits after zone loss, and let clients poll through notification failures.

Reference technology choices

These are replaceable examples, not claims about Google Drive’s implementation.

ConcernOptionsWhy
Metadata storePostgreSQL/MySQL for a shard; Spanner, CockroachDB, or a Vitess-backed relational service at larger scaleStandard SQL is a strong starting point; partition by driveId and accept application-managed sharding, failover, and cross-shard trade-offs as scale grows
Change feed and outboxTransactional outbox to Kafka or Pub/SubAn outbox is a change record written with metadata, then delivered independently and replayably
CacheRedis or MemcachedFast, versioned metadata and effective-ACL cache entries
Chunk storeS3, GCS, or a distributed file storeDurable immutable chunks and direct, signed transfers
Wake-up channelWebSockets plus FCM/APNsLow-latency hints for connected and mobile clients; the feed remains authoritative

Technologies and techniques worth exploring

  • Rabin fingerprints and FastCDC — understand how content-defined boundaries localize edits without using a cryptographic hash at every byte.
  • Merkle trees — compare large local and remote manifests and narrow integrity checks to mismatched subtrees.
  • Raft and consensus-backed transactions — see why metadata leaders provide ordered, durable state changes and what partitions cost.
  • Erasure coding — reduce cold-storage overhead while quantifying repair bandwidth and read amplification.
  • Transactional outbox pattern — publish change events without a fragile dual write between a database and a message broker.
  • End-to-end data-integrity checking — follow checksums through memory, network, storage, replication, and restore rather than trusting one layer.

Key takeaways

  • Immutable chunks make retries, replication, and repair tractable.
  • A transactional manifest commit is the visibility boundary.
  • Direct, resumable transfer keeps large file bytes out of the general API path.
  • Checksums detect corruption, while independent replicas and tested repair recover from it.
  • The storage and repair fleet, not metadata QPS, determines the physical scale.

The governing contract is simple to state and expensive to honor: once a version is acknowledged, every later layer must preserve enough verified information to find, reconstruct, authorize, and restore those exact bytes.

Quiz

Drive design challenge

Can you keep every byte safe?

Five failure scenarios. Make the call before you reveal the answer.

1 / 5
Question 1 of 5

All chunks reached storage, but the client disconnected before commit. What should readers see?