File Sharing System Design: Sync, Storage, and Collaboration at Scale
Dropbox, Google Drive, and OneDrive handle billions of files for hundreds of millions of users. Behind the simple "drag and drop" experience sits a sophisticated distributed system that synchronizes bytes across devices, resolves conflicts, and supports real-time collaboration. This guide breaks down the architecture of a production-grade file sharing system.
Functional Requirements#
- Upload, download, and organize files and folders.
- Automatic sync across all of a user's devices.
- Share files and folders with other users with granular permissions.
- Version history — view and restore previous versions of any file.
- Real-time collaborative editing for supported file types.
- Offline support — edit files without connectivity and sync when back online.
Non-Functional Requirements#
- Durability: 99.999999999% (11 nines) — no file should ever be lost.
- Consistency: Eventual consistency for sync; strong consistency for metadata operations.
- Latency: Small file uploads complete in under 1 second; large files show progress immediately.
- Scale: Support 500M+ users and exabytes of storage.
- Bandwidth efficiency: Minimize data transferred during sync.
High-Level Architecture#
┌───────────┐ ┌──────────────┐ ┌────────────────┐
│ Desktop │─────▶│ API │─────▶│ Metadata │
│ Client │◀─────│ Gateway │◀─────│ Service │
└───────────┘ └──────┬───────┘ └───────┬────────┘
│ │
┌──────▼───────┐ ┌───────▼────────┐
│ Block │ │ Metadata DB │
│ Server │ │ (MySQL/Vitess)│
└──────┬───────┘ └────────────────┘
│
┌──────▼───────┐
│ Block │
│ Storage │
│ (S3/GCS) │
└──────────────┘
The system splits into two planes: the data plane (block server + block storage) handles raw bytes, and the control plane (metadata service + metadata DB) tracks file trees, versions, and permissions.
File Sync: Chunking#
Uploading entire files on every save is wasteful. Instead, the client breaks files into fixed-size chunks (typically 4 MB):
- Split — The client divides the file into chunks and computes a SHA-256 hash for each.
- Check — The client sends the list of chunk hashes to the block server.
- Upload delta — The server responds with which chunks it already has. The client uploads only the missing ones.
- Commit — Once all chunks are stored, the client tells the metadata service to update the file record with the new chunk list.
Chunking enables resumable uploads — if the connection drops, only the incomplete chunk needs to be retried, not the whole file.
Deduplication#
Because chunks are addressed by content hash, identical chunks (even across different users) are stored only once. This is content-addressable storage:
file_A: [chunk_abc, chunk_def, chunk_ghi]
file_B: [chunk_abc, chunk_xyz, chunk_ghi]
→ Only 4 unique chunks stored, not 6
Dedup saves enormous storage costs. Dropbox reported 75%+ storage savings from deduplication in their early architecture. The block storage layer uses reference counting — a chunk is deleted only when no file references it.
Delta Sync#
When a user edits a file, only the changed chunks need to be uploaded. The client computes a rolling hash (e.g., Rabin fingerprint) to detect chunk boundaries that shift gracefully when bytes are inserted or deleted in the middle of a file.
Rolling hash vs. fixed chunking: Fixed-size chunks cause a cascade of changes when bytes are inserted early in a file. Content-defined chunking with a rolling hash keeps most chunk boundaries stable, so a small edit produces only 1-2 new chunks regardless of where the edit occurs.
Metadata Service#
The metadata service is the brain of the system. It stores:
- File tree: Hierarchical namespace (
/Documents/report.pdf) mapped to a flat metadata record. - File metadata:
file_id,name,size,chunk_list,version,created_at,modified_at,owner_id. - Workspace/folder metadata:
folder_id,parent_id,name,permission_set.
The metadata DB uses a relational store (MySQL with Vitess for sharding) because file trees involve parent-child relationships and transactional updates (rename + move must be atomic).
Namespace Operations#
| Operation | Implementation |
|---|---|
| Create file | Insert metadata row; upload chunks |
| Rename | Update name field; no data movement |
| Move | Update parent_id; no data movement |
| Delete | Soft-delete metadata; garbage-collect chunks after retention period |
| List folder | Query by parent_id with pagination |
Block Storage#
Raw chunks are stored in object storage (S3, GCS, or Azure Blob). The block server acts as an intermediary:
- Write path — Client uploads chunk to block server; block server computes hash, checks for duplicates, writes to object storage, returns confirmation.
- Read path — Client requests chunks by hash; block server streams from object storage (with CDN caching for popular files).
For durability, object storage provides cross-region replication. The block server itself is stateless and horizontally scalable.
Conflict Resolution#
When two users (or two devices) edit the same file concurrently, the system must resolve conflicts:
Strategy 1 — Last writer wins (LWW): Simple but lossy. The most recent write overwrites the other. Acceptable for non-collaborative personal files.
Strategy 2 — Conflict copy: If the server detects divergent edits (the base version differs), it saves both versions: report.pdf and report (conflict copy - Alice - Mar 28).pdf. The user manually merges. This is what Dropbox uses.
Strategy 3 — Operational transformation / CRDT: For real-time collaborative editing (Google Docs-style), use OT or CRDTs to merge concurrent edits at the character/operation level without conflicts.
The metadata service tracks a version vector per file. When a client syncs, it sends its last-known version. If the server's version has diverged, it triggers the appropriate conflict strategy.
Sharing and Permissions#
Permissions are stored as ACL (access control list) entries on files and folders:
{
"resource_id": "folder_abc",
"acl": [
{ "principal": "user:alice", "role": "owner" },
{ "principal": "user:bob", "role": "editor" },
{ "principal": "link:public", "role": "viewer", "expiry": "2026-04-30" }
]
}
Permission inheritance: Folders propagate permissions to children. A file's effective permission is the union of its own ACL and its ancestors' ACLs, with the most permissive role winning.
Share links: Generate a unique token that maps to a resource + role. Support expiry, password protection, and download limits.
Permission checks happen at the API gateway for every request, cached in Redis with short TTLs.
Real-Time Collaboration#
For documents that support live co-editing:
- Presence service — Tracks which users have a file open. Broadcasts cursor positions and selections via WebSocket.
- Operation log — Each keystroke or edit is captured as an operation and sent to the collaboration server.
- OT/CRDT engine — Transforms concurrent operations so they converge to the same document state on all clients.
- Persistence — Periodically snapshots the document state to the metadata service and block storage.
The collaboration server is stateful (it holds the in-memory document state for active sessions) and uses consistent hashing to route all editors of the same document to the same server instance.
Versioning#
Every file edit creates a new version entry:
version_id | file_id | chunk_list | created_at | created_by
v7 | f_123 | [c_aa, c_bb, c_cc] | 2026-03-28 14:00:00 | alice
v6 | f_123 | [c_aa, c_bb, c_dd] | 2026-03-27 09:30:00 | bob
v5 | f_123 | [c_aa, c_ee, c_dd] | 2026-03-26 11:00:00 | alice
Because chunks are immutable and content-addressed, old versions share chunks with new versions — storage overhead for versioning is minimal (only the changed chunks are new). A retention policy (e.g., 30-day history, or unlimited for paid plans) governs when old version metadata and orphaned chunks are garbage-collected.
Restore simply updates the file's current chunk_list to point at the old version's chunks.
Offline Support#
The desktop client maintains a local SQLite database mirroring the metadata of synced files, plus a local cache of file content.
Offline workflow:
- User edits a file while offline. The client records the edit in a local journal (write-ahead log).
- When connectivity returns, the client replays the journal against the server.
- If the server's version has changed, conflict resolution kicks in.
The client uses a sync queue that processes changes in order, retrying transient failures with exponential backoff.
Notification and Sync Protocol#
When a file changes on the server, all subscribed clients must be notified:
- Long polling / WebSocket — The client maintains a persistent connection to a notification service. On file change, the server pushes an event with the file ID and new version.
- Sync protocol — The client fetches the delta (list of changed files since its last sync cursor) from the metadata service and downloads only the new/changed chunks.
The sync cursor is an opaque token representing the client's last-known state. This avoids full tree scans on every sync.
Scaling Considerations#
Metadata sharding — Shard the metadata DB by owner_id so all of a user's files land on the same shard, enabling efficient folder listings.
Hot files — Popular shared files (e.g., company-wide docs) create read hotspots. Use CDN caching and read replicas.
Chunk storage tiering — Move infrequently accessed chunks to cheaper storage classes (S3 Glacier, GCS Coldline) automatically.
Multi-region — Replicate metadata and popular chunks across regions. Route users to the nearest region via DNS.
Summary#
A file sharing system is two systems in one: a data plane that stores and deduplicates chunks efficiently, and a control plane that manages the file tree, permissions, versions, and sync state. The elegance lies in content-addressable chunking — it solves dedup, delta sync, versioning, and resumable uploads in one primitive.
Build and explore system designs like this interactively at codelit.io.
This is article #198 in the Codelit engineering blog series.
Try it on Codelit
Chaos Mode
Simulate node failures and watch cascading impact across your architecture
Related articles
Try these templates
Simple Ride-Sharing MVP
A basic ride-sharing app with core components for rider-driver matching.
5 componentsUber Real-Time Location System
Handles 5M+ GPS pings per second using H3 hexagonal geospatial indexing.
6 componentsInstagram-like Photo Sharing Platform
Full-stack social media platform with image processing, feeds, and real-time notifications.
12 componentsBuild this architecture
Generate an interactive architecture for File Sharing System Design in seconds.
Try it in Codelit →
Comments