Dropbox Design — Hash Collisions That Corrupted User Files
A chunking bug caused SHA-256 collisions, returning garbage for 4MB blocks.
20+ years shipping large-scale distributed systems. Notes here come from systems that actually shipped.
- Dropbox uses client-server sync with block-level chunking (4 MB blocks) for efficient uploads
- Deduplication via SHA-256 hashes eliminates duplicate storage across all users
- Metadata service stores file hierarchy in a scalable key-value store (like MySQL sharded)
- Delta sync transfers only changed parts of files, not entire files
- Conflict resolution uses last-writer-wins for simple cases and creates conflict copies for complex merges
- Notification system uses long-polling to detect remote changes within seconds
Imagine you have a magic folder on your desk. Whatever paper you drop in it instantly appears in the exact same folder on your friend's desk across the world — and on your phone too. If you both edit the same paper at the same time, the magic folder figures out how to combine your changes without losing either person's work. Dropbox is that magic folder, built for hundreds of millions of people simultaneously.
File synchronization sounds deceptively simple until you're the one building it at scale. Dropbox processes over 1.2 billion file syncs per day, maintains over 500 petabytes of user data, and must deliver sub-second sync latency while handling everything from a 2 KB sticky note to a 50 GB video file. The gap between 'copy a file to the cloud' and 'build a production sync platform' is enormous, and every corner of that gap has killed startups.
The core problem is elegant to state and brutal to solve: multiple clients, on different networks, with different OS file systems, modifying a shared namespace — and every client must converge to the same state, eventually, without data loss, even when the network disappears for days. Throw in deduplication to save petabytes of storage, delta sync to save bandwidth, and conflict resolution that doesn't confuse non-technical users, and you have a genuinely hard distributed systems challenge.
By the end of this article you'll be able to walk into a senior system design interview and draw the complete Dropbox architecture from memory — the client sync engine, the block store, the metadata service, the notification system, and the conflict resolution strategy. More importantly, you'll understand why each component exists and what breaks if you cut corners on any of them.
What Dropbox Design Really Means — Content-Addressable Storage at Scale
Dropbox design is a content-addressable file storage system where each file is identified by the cryptographic hash (SHA-256) of its contents, not its name or path. The core mechanic: when a user uploads a file, the system computes its hash, checks if that hash already exists in storage, and if so, simply links the user's account to the existing block — deduplicating data across all users. This is the foundation of Dropbox's efficiency: storing one copy of a file shared by millions.
In practice, this means every file is split into fixed-size blocks (typically 4 MB), each block hashed independently. The system maintains a block-to-reference count mapping and a user-to-block mapping. Writes are append-only; modifications create new blocks. The critical property: hash collisions are astronomically unlikely with SHA-256 (2^-256 probability), but if one occurs, two different blocks map to the same hash, causing the system to serve the wrong block to users. This is the single point of failure in the design.
You use this design when you need massive deduplication across users — cloud storage, backup services, or any multi-tenant file system. It matters because it reduces storage costs by 10-100x for shared content, but it trades on the absolute correctness of the hash function. In production, you must validate that your hash function is collision-resistant and that your deduplication logic handles edge cases like partial uploads and concurrent writes without corrupting reference counts.
Core Architecture: Client ↔ Server Sync Model
Dropbox uses a simple but robust pull-based sync model. The client maintains a local file system watcher (inotify on Linux, FSEvents on macOS, ReadDirectoryChangesW on Windows). When a change is detected, the client builds a local file tree and compares it with the server's tree.
The server stores metadata in a horizontally sharded MySQL cluster. Each user's files are partitioned by user ID. The metadata schema includes: file_id, parent_id, name, hash (SHA-256 of file content), size, and mtime. The block store is an Amazon S3-compatible object store, with blocks referenced by content hash.
The client syncs in three phases: 1) Upload changed blocks (only if hash not in block store), 2) Update metadata (send new checksums to server), 3) Poll for remote changes (every 3 seconds via long-polling HTTP). Server notifies clients of changes by returning the updated file tree delta.
When the metadata update succeeds, the server broadcasts a notification to all connected clients via the long-poll notification service, indicating that the user's file tree has changed.
But here's the nuance: the server doesn't push. It holds the HTTP response open (long-poll) until there's a change or timeout. This keeps connection overhead low. If you implement this naively, you'll hit connection limits on your load balancer. Dropbox's notification servers use a consistent hash ring to route the same user to the same server, so the server can track which users are connected without synchronising state across all servers.
Block Store: Chunking, Deduplication & Delta Sync
Every file is split into 4 MB blocks. The last block is often smaller. Each block gets a SHA-256 hash. The block store is a content-addressable store: blocks are stored at paths like /blocks/{hash[0:2]}/{hash[2:4]}/{hash}. This two-level prefix directory avoids huge single directories on S3.
Deduplication is trivial: if the hash already exists in the block store, we skip upload. Since Dropbox stores over 500 PB with only ~200 PB of unique blocks (60% dedup ratio), this saves billions of dollars in storage costs.
Delta sync: when a file is edited, the client recomputes block boundaries and uploads only the blocks that changed. However, small edits can shift all subsequent block boundaries. Dropbox uses a content-defined chunking algorithm (rolling hash like CDC) to keep block boundaries stable across edits. This means editing one byte in a 500 MB video changes only one block, not all blocks after it.
- If 10 users upload the same cat video, only one copy is stored.
- Block store is a giant map from hash → data. Uploading a block with an existing hash is a no-op.
- The 60% dedup ratio means every 100 PB of logical storage costs only 40 PB of physical storage.
- But dedup has a hidden cost: integrity checks. A hash collision can destroy data (see production incident).
- Always add a CRC or byte comparison on the first few bytes before returning cached data.
Metadata Service: File Tree Storage & Synchronization
The metadata service is the single source of truth for file hierarchy. Each user has a file tree stored in a relational database (MySQL, sharded by user_id). The tree is represented as adjacency list: each row has file_id, parent_id, name, and content_hash. The root of each user's tree is a special entry with parent_id = NULL.
When the client uploads new blocks and gets their hashes, it sends a transaction to the metadata service: "replace the content_hash of file X with new_hash Y". The server validates that the new hash actually exists in the block store (otherwise reject). Then it logs the change in a journal table.
The journal table is the key to conflict resolution and delta sync. Each change is a row: (change_id, user_id, file_id, new_hash, timestamp). The client syncs by requesting changes after a known change_id. The server returns all changes since that ID. This is a classic changelog pattern.
Read operations (browsing folders) are served from a read replica to reduce load on the primary. Write operations go to the primary. Eventual consistency means a write might take up to 100ms to propagate to read replicas — acceptable because the client's next poll will see the latest state.
Conflict Resolution: When Two Clients Edit the Same File
The classic problem: user A and user B both edit the same file while offline. When they come online, the server has two versions. Dropbox uses a simple strategy: the first uploaded version wins as the canonical copy. The second version is saved as a conflict copy (e.g., "report.docx (A's conflicted copy 2026-04-22).docx").
This works because it never loses data, and users can manually merge if needed. For office documents, Dropbox offers automatic merge via a custom diff engine (similar to 3-way merge in version control). But that's only for specific file types (Office docs, Google Docs, etc.). For plain text or binaries, it's last-writer-wins with conflict copy.
The resolution happens at the metadata level: when the server receives a write for a file, it checks the version (an incrementing counter). If the version in the update doesn't match the current server version, it's a conflict. The server applies the update and creates a new file entry for the conflict copy.
What about concurrent writes while both are online? The server's database transaction ensures serializability. One client's update succeeds, the other gets a 409 Conflict response. The client must then fetch the new version and offer to merge.
One detail that often trips people up: conflict copies are created at the metadata level, not the block level. The server simply creates a new file row with the conflicting content_hash. No duplicate block storage is needed because deduplication already handles the identical blocks. The only cost is the metadata row and the filename.
- Each conflict copy is a new file entry with the same content_hash.
- Block store already has the data; no extra bytes are stored.
- But metadata storage grows linearly with conflict copies — clean them up periodically.
- Non-technical users often don't notice conflict copies; surface them clearly in the UI.
- Add a 'sync history' feature to show all versions including conflicts.
Scaling to 700M+ Files per Day: The Infrastructure Behind Dropbox
Dropbox's infrastructure runs across multiple data centers and AWS (for block storage). Key scaling numbers (as of 2020s): - 500+ PB of user data stored. - 700 million+ files uploaded per day. - 1.2 billion sync operations per day. - Metadata stored in 100+ MySQL shards (each ~5 TB). - Block store: custom object store (called 'Magic Pocket') built on top of JBOD servers with replication.
Scaling challenges: 1. Metadata sharding: Users are mapped to shards by user_id hash. Hot users (with millions of files) are split across multiple shards via sub-sharding. This required a custom rebalancing tool that moves user chunks between shards without downtime. 2. Block store throughput: A single 10 GB file upload generates 2560 blocks (4 MB each). For large files, clients upload blocks in parallel (up to 10 concurrent uploads per file). The block store must handle millions of small PUT requests per second. Solution: use a distributed key-value store (like Dynamo-inspired database) with in-memory tiers for hot blocks. 3. Notification scalability: Long-polling connections are handled by a dedicated notification service (not metadata). Each notification server handles 500k+ connections. They use a consistent hash ring to route the same user to the same notification server, so the server can track which users are connected. 4. Cache layer: Block store uses a CDN-like edge cache for frequently accessed blocks. The metadata service uses memcached clusters to cache file tree lookups.
- Top 1% of users account for 40% of block storage.
- 10% of users generate 80% of sync operations due to automated software syncing (e.g., iOS backups).
- Caching works well because most files are read once and never read again (long tail).
- Hot blocks (popular shared files) are cached aggressively.
- Cold blocks (personal archives) live in slow, cheap storage.
Client Sync Engine: Local File Monitoring and Upload Pipeline
The Dropbox client runs as a background process on each device. It uses operating system file system event APIs (inotify on Linux, FSEvents on macOS, ReadDirectoryChangesW on Windows) to detect file changes in the designated Dropbox folder. When a change is detected, the client does not immediately upload. It waits for a quiet period (typically 100ms) to batch rapid edits (e.g., during save-as). Then it computes the file tree diff and determines which blocks have changed.
For new files, it chunks the entire file and uploads all blocks. For modifications, it uses content-defined chunking to detect changed block boundaries. Uploads are parallelized (up to 10 concurrent connections per file) and retried with exponential backoff. Each block upload includes a SHA-256 hash and file offset. The block store responds with a success or conflict.
After all blocks are uploaded, the client sends a metadata update request to the server with the new file hash. The server validates that all block hashes exist in the block store, then commits the metadata change and appends to the changelog.
One critical detail: the client must handle the case where the server rejects the metadata update because another client already updated the same file. The client then receives the current server state and must merge or create a conflict copy.
- A 100ms quiet period batches multiple saves from the same application (e.g., auto-save in editors).
- If set too low, each keystroke triggers a full file scan and upload wave.
- If set too high, the user sees a delay between saving and the file appearing on other devices.
- Dropbox's default 200ms quiet period works well for most document types.
- Rule: make the quiet period configurable per device based on file type patterns.
System Requirements: The Contract That Prevents Midnight Pager Duty
Before you write a single line of sync logic, nail down the requirements. Every production incident I've debugged traces back to a fuzzy requirement. Functional requirements define what the system does: upload, download, share, create directories, sync across devices. Non-functional requirements define how well it does it. Availability means 99.999% uptime. That's 5 minutes of downtime per year. Durability means your cat photos survive a data center fire. Reliability means the same input always gives the same output. Scalability means the system doesn't fall over when 100 million daily active users upload files simultaneously. ACID properties ensure file operations don't corrupt metadata. Skip this step, and you'll be debugging data loss at 3 AM. Write them down. Make them measurable. Then build to them.
Capacity Estimation: Don't Guess, Calculate — Your S3 Bill Depends on It
Blindly scaling costs money. Capacity estimation forces you to think about numbers before you build. Start with assumptions: 500 million total users, 100 million daily actives. Each user stores 200 files averaging 100 KB. That's 100 billion files and 10 PB of storage. Now calculate bandwidth: 1 million active connections per minute means 1.67 KB/s per user at peak. That's 1.67 GB/s total egress. Choose your cloud provider accordingly. Metadata database needs to handle 100 billion rows. That's not a single PostgreSQL instance. Partition. Shard. Use DynamoDB or Cassandra. Storage estimation tells you the infrastructure cost before you commit. It tells your CFO how much to budget. It tells your ops team what hardware to order. Skip this step, and your system will either run out of space or cost twice what it should.
High-Level Design: The Skeleton Your Team Will Fight Over in Architecture Reviews
The HLD is the map. Without it, each engineer builds a different system. Start with the user flow: client uploads a file. The client contacts the Upload Service. That service authenticates the user, validates the file size, and generates a presigned URL for direct upload to S3. The client uploads the file directly to S3 using that URL. No server-side proxy for large files — that's a bottleneck. Meanwhile, metadata goes to a separate database: file name, size, modification time, parent directory. A Task Runner picks up the metadata change and triggers sync to other devices. Downloads follow the reverse path: client requests file metadata from the Metadata Service, gets a presigned S3 URL, and downloads directly. This pattern keeps the business logic servers stateless and scalable. Each component has one job. No monoliths. No shared state. Three services: Upload, Metadata, Sync. That's the skeleton. Add muscle later.
The 4 MB Block That Crashed the Sync Engine
- Even with strong hashing, always verify block content on read for mission-critical data.
- Never trust that deduplication is lossless without an integrity check layer.
- Add a block-level CRC checksum stored alongside the hash for double verification.
- Always implement a background integrity check service that periodically verifies blocks against their hashes.
dd if=/dev/zero bs=1M count=10 | nc -w5 blockstore-host 443 to measure throughput.dropbox filestatus /path/to/filegrep 'upload.*failed' ~/.dropbox/error.logKey takeaways
Common mistakes to avoid
7 patternsMemorising syntax before understanding the concept
Skipping practice and only reading theory
Assuming deduplication is always lossless
Using push notifications instead of polling for sync
Not planning for clients that disappear for months
Using a single metadata database without sharding
Not handling simultaneous upload of the same block by two clients
Interview Questions on This Topic
How would you design a file synchronization service like Dropbox? Focus on the sync algorithm and conflict resolution.
Frequently Asked Questions
20+ years shipping large-scale distributed systems. Notes here come from systems that actually shipped.
That's Real World. Mark it forged?
10 min read · try the examples if you haven't