Dropbox
Design a file-sync and storage service with chunking, deduplication, and conflict resolution.
Problem Statement
Design Dropbox, a cloud file storage and synchronization service. Users install clients on laptops and phones, create or edit files locally, and expect those changes to appear on every device and for collaborators with low delay. The system must store file contents durably, preserve file versions, support sharing and permissions, and recover deleted or overwritten data.
At interview scale, assume hundreds of millions of users, billions of file mutations per day, exabytes of stored data, and many clients that are intermittently offline. The central challenge is not just uploading whole files. A strong design chunks files into blocks, stores blocks by content hash for deduplication, tracks file metadata and version histories separately, syncs only changed blocks, and notifies clients quickly when remote changes happen.
The default design should optimize for durable storage, bandwidth-efficient sync, metadata correctness, and predictable conflict resolution. Optional features such as selective sync, team folders, shared links, ransomware recovery, and CDN acceleration should layer on top without weakening the core invariant that file versions map to immutable block lists.
Business use case
Dropbox lets users and businesses treat cloud storage as an always-available folder. It improves productivity by making files available across devices, allowing teams to collaborate without manual email attachments, and protecting users from local disk failure.
For enterprises, the same platform becomes a managed content layer with audit logs, sharing controls, data retention, device management, and restore workflows. Efficient sync and deduplication directly reduce storage, bandwidth, and support costs at exabyte scale.
Functional Requirements
Upload new files and modified file contents from desktop, mobile, and web clients.
Download files and keep multiple devices synchronized with the latest visible version.
Chunk files into blocks and upload or download only missing or changed blocks.
Store and restore historical file versions and deleted files within a retention window.
Support shared folders, shared links, permissions, and owner or admin revocation.
Detect remote changes through notification, long-poll, or streaming sync channels.
Handle concurrent edits with deterministic conflict resolution and user-visible conflicted copies.
Support selective sync and offline clients that later reconcile with the server.
Non-Functional Requirements
Sync latency
Small metadata changes should become visible to online peer clients in under 5 seconds p95. Small file edits should finish upload, commit, notification, and first download start in under 30 seconds p95 on a healthy network.
Durability
Committed file versions must not be lost. Store metadata in replicated databases, store blocks in object storage with multi-zone durability or erasure coding, verify block hashes, and keep backups or journal replay for metadata recovery.
Availability
Users should still read already-synced local files during server outages, and cloud downloads should target 99.99 percent availability. Metadata writes can degrade more carefully than reads, but the system must avoid accepting commits that cannot be durably recovered.
Scalability
Scale metadata, block upload, block download, notification fanout, and background compaction independently. File metadata operations are small and consistency-sensitive, while block storage is bandwidth-heavy and object-store-oriented.
Bandwidth efficiency
Clients should avoid re-uploading bytes the service already has. Use file chunking, content-addressed block hashes, server-side missing-block checks, compression where appropriate, and CDN downloads for popular shared content.
Consistency
Each file path needs a clear latest version, atomic metadata commits, and monotonic change tokens per namespace. Cross-device propagation can be eventually consistent, but clients must converge to the same ordered journal after reconnecting.
Security and privacy
The service stores sensitive personal and enterprise data. Enforce authentication, namespace permissions, secure shared links, encryption in transit and at rest, auditability, and careful deduplication boundaries to avoid cross-tenant information leakage.
Capacity Estimation
Assumptions
Assume 800M registered users, 100M daily active users, 2B file change commits per day, an average logical changed payload of 2 MB per commit, a 4 MB maximum block size, and 1.2 changed block references per commit after chunking small and medium files.
Assume deduplication, compression, failed-upload cleanup, and version retention reduce unique physical block ingestion to 40 percent of logical changed bytes. Use a 5x peak multiplier over average for upload and metadata traffic. Assume 50M concurrently connected clients and 2 devices notified per committed change on average.
Daily active users
100M
Users with at least one client or web session active that day
File commits
2B per day
Creates, updates, deletes, moves, and restores that produce metadata journal entries
Average commit QPS
23,000 commits per second
2B divided by 86,400 seconds
Peak commit QPS
115,000 commits per second
5x average peak
Logical changed data
4 PB per day
2B commits times 2 MB average changed payload
Unique physical ingest
1.6 PB per day
40 percent of logical bytes after deduplication, compression, and cleanup
Block references
2.4B per day
2B commits times 1.2 block references per commit
Notification fanout
46,000 events per second average
2B commits times 2 devices divided by 86,400 seconds
Metadata growth
2 to 3 TB per day raw
Version records, block references, path journal, shares, and indexes before replication
Annual physical block growth
580 PB raw before redundancy
1.6 PB per day times 365 days; accumulated fleet storage reaches exabytes
Calculations
- Commits: 2B file commits per day divided by 86,400 seconds is about 23,148 commits per second, rounded to 23,000.
- Peak metadata writes: applying a 5x multiplier gives about 115,000 commits per second.
- Logical changed data: 2B commits times 2 MB is 4B MB per day, which is about 4 PB per day.
- Deduplication savings: if only 40 percent becomes unique stored blocks, object storage ingests about 1.6 PB per day instead of 4 PB. That implies about 60 percent savings from duplicate files, repeated blocks, compression, and abandoned upload cleanup.
- Block references: 2B commits times 1.2 block references is 2.4B ordered references per day. At roughly 64 bytes per reference before indexes, block-reference metadata alone is about 154 GB per day raw.
- Version metadata: if each commit stores about 1 KB of path, actor, timestamps, permissions snapshot pointer, and version metadata, 2B commits add about 2 TB per day raw before replication and indexing.
- Notifications: 2B commits times 2 target devices is 4B device notifications per day. 4B divided by 86,400 seconds is about 46,000 notification events per second average, with peaks around 230,000 per second.
- Storage: 1.6 PB per day times 365 days is about 584 PB per year before redundancy. With erasure coding, replication, thumbnails, indexes, and retention, a mature service plans in exabytes.
- Long-poll load: 50M connected clients renewing a long-poll every 60 seconds would create about 833,000 renewals per second if implemented naively, so persistent connections, jitter, and regional notification shards are required.
API Design
/api/v1/upload-sessionsStarts an upload session for a file mutation. The server returns the block hashes it already has so the client uploads only missing blocks.
Request
{
"namespaceId": "ns_123",
"path": "/Designs/spec.pdf",
"clientBaseRev": "rev_9182",
"fileSizeBytes": 9437184,
"blockSizeBytes": 4194304,
"blockHashes": ["sha256_a", "sha256_b", "sha256_c"]
}
Response
{
"uploadSessionId": "upl_456",
"missingBlockHashes": ["sha256_b"],
"expiresAt": "2026-07-26T13:10:48Z"
}
201— Upload session created400— Invalid path, revision, or block manifest401— Authentication required403— No write permission for the namespace or path409— Client base revision is stale and requires conflict handling429— Upload rate limit exceeded
/api/v1/blocks/{blockHash}Uploads one missing content-addressed block. The server verifies that the uploaded bytes hash to the requested block hash before making the block available for commit.
Request
Binary block payload up to 4 MB with headers: Content-Type: application/octet-stream Upload-Session-Id: upl_456 Block-Hash: sha256_b
Response
{
"blockHash": "sha256_b",
"sizeBytes": 4194304,
"stored": true
}
200— Block already existed or was stored successfully400— Payload hash or size does not match401— Authentication required403— Upload session is not authorized for this block413— Block exceeds maximum size
/api/v1/files/commitCommits the metadata change after all required blocks exist. This creates a new file version and appends an ordered journal entry for sync clients.
Request
{
"uploadSessionId": "upl_456",
"namespaceId": "ns_123",
"path": "/Designs/spec.pdf",
"clientBaseRev": "rev_9182",
"blockHashes": ["sha256_a", "sha256_b", "sha256_c"],
"mode": "overwrite-if-current"
}
Response
{
"fileId": "file_789",
"newRev": "rev_9183",
"journalSeq": 23881231,
"conflict": false
}
201— New file version committed400— Commit manifest is invalid403— Caller lacks write permission409— Base revision conflict; caller should create a conflicted copy or merge422— One or more referenced blocks are missing
/api/v1/sync/deltaReturns ordered changes for a namespace after the client's last known cursor. Clients use this endpoint after reconnecting or after receiving a notification.
Response
{
"namespaceId": "ns_123",
"fromCursor": "cur_abc",
"nextCursor": "cur_def",
"hasMore": true,
"changes": [
{
"journalSeq": 23881231,
"type": "file_updated",
"fileId": "file_789",
"path": "/Designs/spec.pdf",
"rev": "rev_9183"
}
]
}
200— Delta returned400— Cursor is invalid or too old401— Authentication required403— No read permission for namespace410— Cursor expired; client must rescan the namespace
/api/v1/files/{fileId}/downloadReturns the latest visible file version, a selected historical revision, or signed block download URLs. Large downloads can be served by object storage and CDN.
Response
{
"fileId": "file_789",
"rev": "rev_9183",
"sizeBytes": 9437184,
"blockSizeBytes": 4194304,
"blocks": [
{
"blockHash": "sha256_a",
"sizeBytes": 4194304,
"downloadUrl": "https://cdn.example.com/blocks/sha256_a"
}
]
}
200— Download manifest returned206— Partial byte range returned by block download endpoint401— Authentication required403— No read permission404— File or version not found
/api/v1/sharesCreates a shared folder permission or shared link. The metadata service records the policy and later enforces it on list, sync, and download operations.
Request
{
"resourceId": "file_789",
"resourceType": "file",
"principal": "user@example.com",
"role": "viewer",
"expiresAt": "2026-08-26T00:00:00Z"
}
Response
{
"shareId": "shr_321",
"resourceId": "file_789",
"role": "viewer",
"status": "active"
}
201— Share created400— Invalid principal or role401— Authentication required403— Caller cannot share this resource409— Conflicting share policy already exists
Separate block transfer from metadata commit. A block upload is idempotent and content-addressed, while a file commit is a consistency-sensitive metadata transaction. Clients should be able to retry upload sessions, resume missing blocks, and commit only after the server confirms that all referenced blocks exist.
For sync, clients should not poll entire folder trees. They keep a namespace cursor, receive a notification that the cursor has advanced, and call the delta API to fetch ordered changes. Download APIs can return signed block URLs so large bytes flow through object storage and CDN instead of the metadata service.
Database Design
Store file bytes and file metadata separately. Blocks are immutable objects addressed by cryptographic hash. File versions are metadata records that point to ordered block references. A namespace journal gives every client a monotonic stream of changes to replay.
The metadata database must support transactional updates per namespace or per file path, compare-and-swap on base revisions, and efficient listing by parent folder. The block index must support existence checks, reference accounting, and garbage collection without blocking the commit path.
| namespace_id | uuid | Primary key for a user root, team space, or shared folder |
| owner_id | uuid | User or team that owns the namespace |
| root_folder_id | uuid | Root folder node |
| current_journal_seq | bigint | Latest committed sequence for delta sync |
| created_at | timestamp | Namespace creation time |
| status | varchar(20) | Active, suspended, locked, or deleted |
| file_id | uuid | Stable logical identity across renames and versions |
| namespace_id | uuid | Partition and permission boundary |
| parent_folder_id | uuid nullable | Folder hierarchy parent |
| name | varchar(255) | Current display name within parent folder |
| node_type | varchar(16) | File or folder |
| latest_rev | varchar(64) | Current visible revision |
| deleted_at | timestamp nullable | Soft delete marker for restore |
| updated_at | timestamp | Last metadata mutation time |
| rev | varchar(64) | Primary key for an immutable version |
| file_id | uuid | Logical file identity |
| namespace_id | uuid | Used for partition-local journal ordering |
| actor_user_id | uuid | User or service that created the version |
| size_bytes | bigint | Logical file size |
| content_hash | varchar(64) | Hash over the ordered block list and file length |
| created_at | timestamp | Commit time |
| journal_seq | bigint | Namespace sequence emitted to sync clients |
| rev | varchar(64) | File version that owns this ordered reference |
| block_index | int | 0-based order in the file |
| block_hash | varchar(64) | Cryptographic hash of immutable block bytes |
| offset_bytes | bigint | Logical byte offset |
| size_bytes | int | Block length, usually up to 4 MB |
| block_hash | varchar(64) | Primary key for content-addressed storage |
| size_bytes | int | Stored block size |
| storage_uri | text | Object-store bucket and key or erasure-coded location |
| ref_count_estimate | bigint | Approximate references for garbage collection |
| first_seen_at | timestamp | First successful verified upload |
| encryption_key_id | varchar(128) | Key envelope or tenant key reference |
| share_id | uuid | Primary key for shared link or explicit ACL entry |
| resource_id | uuid | File, folder, or namespace being shared |
| principal_id | uuid nullable | Target user, group, team, or null for link share |
| role | varchar(32) | Viewer, editor, owner, or admin |
| expires_at | timestamp nullable | Optional link or permission expiration |
| created_by | uuid | Actor who created the share |
| status | varchar(20) | Active, revoked, expired, or disabled |
Indexes
- file_nodes.namespace_id, parent_folder_id, name supports folder listing and enforces unique names inside a folder.
- file_nodes.namespace_id, latest_rev supports lookup of the current visible file version.
- file_versions.file_id, created_at supports version history and restore.
- file_versions.namespace_id, journal_seq supports delta sync by namespace cursor.
- version_blocks.rev, block_index returns the ordered block list for a file version.
- blocks.block_hash is the primary lookup for deduplication and missing-block checks.
- shares.resource_id and shares.principal_id support permission evaluation and user sharing dashboards.
Relationships
A namespace contains file nodes and a journal sequence. A file node points to one latest revision, while file_versions stores immutable historical revisions. Each revision has many ordered version_blocks, and each version block points to one immutable block object. Shares attach permissions to files, folders, or namespaces and are evaluated before metadata or block download access is granted.
NoSQL alternatives
At large scale, split the logical schema across stores. Metadata can live in Spanner, FoundationDB, CockroachDB, or a sharded relational system because commits need transactions and ordered namespace journals. Block existence and reference metadata fit DynamoDB, Bigtable, or Cassandra keyed by block hash. Actual bytes belong in object storage such as S3, Azure Blob Storage, GCS, or an internal erasure-coded blob store.
Avoid putting object bytes in the metadata database. Also avoid relying on one global transaction for block upload and file commit. The commit only needs to verify that referenced blocks are durably present, then append metadata and journal entries atomically within the namespace.
High-Level Architecture
The metadata path commits file versions and namespace journal entries. The data path moves immutable content-addressed blocks through the Block Service, Object Store, and CDN. Notifications tell clients when to fetch deltas, but clients still use the metadata journal as the source of truth.
Dropbox has two very different planes. The control plane is metadata: paths, folders, revisions, permissions, cursors, and journals. It needs transactions, clear conflict handling, and ordered per-namespace changes. The data plane is block transfer: large immutable chunks addressed by hash, stored in object storage, and downloaded through CDN when possible.
Clients are active participants in the design. They watch local filesystem changes, split files into blocks, compute hashes, ask the server which blocks are missing, upload only missing blocks, and then commit a new metadata version. Remote changes are discovered through notification channels, but correctness comes from replaying the delta journal using cursors.
This separation lets the system scale cheaply. Popular blocks can be cached at the edge, duplicate blocks are stored once, metadata services can be sharded by namespace, and notification outages do not corrupt state because clients can always fall back to polling delta cursors.
Request Flow
- 1
Client detects a local file change
The desktop or mobile sync engine receives an OS filesystem event, waits briefly to avoid reading a file still being written, and scans the changed file. It records the local path, previous known revision, file size, modified time, and user namespace.
- 2
Client chunks the file and computes hashes
The client splits the file into blocks, commonly up to 4 MB each, computes a cryptographic hash for every block, and computes a file content hash over the ordered block list. Only changed blocks need to be uploaded.
- 3
Server reports missing blocks
The client starts an upload session with the block hash manifest. The Block Service checks the block index and returns hashes that are not already present or not visible to this upload session. Existing blocks are reused through deduplication.
- 4
Client uploads missing blocks
For each missing block, the client uploads bytes to the Block Service. The server streams the payload, recomputes the hash, rejects mismatches, writes the block to object storage, and records the block hash in the block index.
- 5
Metadata commit creates a new version
After all blocks are present, the client calls the commit endpoint with the base revision and ordered block list. The Metadata Service performs a compare-and-swap against the current file revision, creates a new immutable file version, updates the file node, and appends a namespace journal entry.
- 6
Conflict is handled if the base revision is stale
If another client already committed a different version, the server returns a conflict. The client can create a conflicted copy with a deterministic name, ask the user to merge, or apply product-specific merge logic for simple file types.
- 7
Remote clients receive a notification
The metadata commit publishes a change event to a queue. Notification shards wake connected clients that subscribe to the affected namespace and tell them that their cursor has advanced. The notification does not contain all file bytes.
- 8
Remote clients fetch deltas and download blocks
Each client calls the delta API with its last cursor, updates its local metadata view, compares block hashes against its local block cache, and downloads only missing blocks through signed URLs, object storage, or CDN.
- 9
Version history and restore remain available
Historical file_versions and block references are retained according to policy. A restore operation creates a new metadata commit pointing to an older version's block list rather than mutating history in place.
Core Components
Sync Client
Watches local changes and reconciles them with cloud state.
The client owns filesystem watching, chunking, hashing, local block cache, upload retries, download scheduling, offline queues, and user-visible conflict copies. It should be conservative: never delete local data solely because a notification was missed, and always reconcile against server cursors.
Sync Service
Coordinates upload sessions, delta sync, and client state transitions.
This stateless service accepts manifests, routes block checks to the Block Service, routes commits to the Metadata Service, returns delta pages, and applies rate limits. It keeps metadata operations separate from bulk block transfer.
Metadata Service
Maintains the authoritative file tree, versions, permissions, and journals.
The Metadata Service performs transactional commits per namespace, verifies base revisions, enforces ACLs, updates latest file pointers, appends journal entries, and supports restore. It is the source of truth for what file version is visible.
Block Service
Stores and verifies immutable content-addressed blocks.
The Block Service checks whether a block hash is already present, verifies uploaded bytes against the declared hash, writes blocks to object storage, records storage locations, and exposes signed download manifests. It should be horizontally scalable and bandwidth-aware.
Object Store
Durably stores immutable block payloads.
Object storage holds the actual bytes, usually with multi-zone replication or erasure coding. Blocks are immutable, so CDN caching is safe. Lifecycle policies move cold versions to cheaper tiers while preserving restore windows.
Notification Service
Wakes clients when subscribed namespaces have new changes.
Notification shards maintain long-poll or streaming connections, map users and devices to namespaces, consume change events, and notify clients that a cursor advanced. They do not decide correctness; clients still fetch deltas from the Metadata Service.
Block Index
Maps block hashes to object locations and lifecycle metadata.
The block index supports deduplication, missing-block checks, reference accounting, integrity scans, and garbage collection. It should be partitioned by block hash and designed for high read and conditional-write throughput.
Change Event Queue
Decouples metadata commits from notification fanout and background workflows.
Kafka, Pub/Sub, Kinesis, or a similar log receives durable change events. Consumers drive notifications, search indexing, audit logs, ransomware detection, thumbnail generation, and analytics without slowing the commit transaction.
Deep Dive
File chunking strategy
Chunking determines bandwidth efficiency, deduplication ratio, and client CPU cost. Fixed-size blocks such as 4 MB are simple: a changed 20 MB file becomes about five blocks, and a small edit often affects one block. The drawback is boundary shift. If a byte is inserted near the beginning of a large file, every following fixed block may change even though most content is identical.
Content-defined chunking uses a rolling hash to choose boundaries based on the data itself. It improves deduplication for insertions and shifted content, but it adds CPU cost, more complicated manifests, and variable block sizes. Many interview answers choose fixed 4 MB blocks for operational simplicity, then mention content-defined chunking for workloads where insertions in large files are common.
The client should keep a local block cache and avoid recomputing hashes for unchanged files when reliable filesystem metadata is available. Still, correctness must rely on content hashes, not only timestamps, because clocks and filesystem events can be unreliable.
Content-addressable storage and deduplication
Each block is named by a cryptographic hash of its bytes. If two users upload the same block, the Block Service can store one physical copy and let multiple file versions reference it. This is powerful for common binaries, shared team files, synced photos, and repeated edits that preserve most blocks.
Deduplication has boundaries. Global dedup maximizes savings but can leak information if an attacker can infer that a block already exists. Safer designs deduplicate within a tenant, within a storage region, or only after authorization checks. The server must also verify uploaded bytes because clients cannot be trusted to claim arbitrary hashes.
Hash collisions are extremely unlikely with SHA-256, but the system should still treat the hash as an integrity check, store block size, and optionally verify stronger content fingerprints for critical paths. Blocks should be immutable once written; a new byte sequence gets a new hash and a new object.
Metadata commits, journals, and versioning
The file tree is not stored as mutable bytes in object storage. It is metadata: namespace, folder hierarchy, file nodes, latest revision pointers, historical revisions, permissions, and journal sequence numbers. A commit should atomically create the version record, attach ordered block references, update the file node, and append a journal event.
The namespace journal is the sync source of truth. A client with cursor 100 asks for changes after 100, receives ordered events, applies them locally, and stores the next cursor. If the cursor is too old because compaction removed old journal pages, the client performs a full rescan of metadata for that namespace.
Restores should not mutate old history. Restoring a prior version creates a new latest revision that points to the old block list. This keeps auditability clear and avoids races with clients that already observed newer revisions.
Delta sync and download planning
Delta sync means only changed metadata and missing blocks move over the network. Upload starts with a manifest of hashes, the server returns missing hashes, and the client uploads only those blocks. Download starts with the delta journal, then the client compares the required block hashes against its local block cache.
Clients need a scheduler. User-opened files and small metadata changes should download first. Large media, cold folders, and selective-sync excluded paths can wait. The scheduler should pause on metered networks, resume partial downloads, back off on errors, and avoid monopolizing user bandwidth.
For very large files, block-level resume is essential. A 10 GB file should not restart from zero after a laptop sleeps. The manifest, block hashes, and committed revision give the client a precise checklist of what remains.
Notifications, long-poll, and convergence
The Notification Service improves latency but should not be required for correctness. It tells clients that something changed, usually by namespace and cursor watermark. Clients then call the delta API to fetch authoritative ordered changes.
Long-poll is common because it works through firewalls and mobile networks. A client opens a request that waits until a change occurs or a timeout expires. To scale to tens of millions of clients, shard connections by user or namespace, use jittered reconnects, and keep payloads tiny. WebSockets or HTTP streaming can reduce reconnect churn but add connection management complexity.
If notifications are dropped, clients still converge through periodic delta polling. If duplicate notifications arrive, the cursor makes processing idempotent. This separation prevents the notification layer from corrupting file state.
Conflict resolution for concurrent edits
Concurrent edits are unavoidable because clients work offline. The server compares the client's base revision with the current latest revision. If they match, the commit advances the file. If they differ, the server rejects overwrite-if-current and asks the client to create a conflicted copy or run a merge flow.
A typical default is last writer does not silently win for opaque binary files. Instead, create a filename such as spec conflicted copy from Alice laptop and preserve both versions. For text documents or product-owned collaborative formats, a higher-level merge engine can combine changes, but generic Dropbox-style storage should not assume it can safely merge arbitrary bytes.
Conflicts should be visible in the metadata journal so every device converges to the same files. Users can later delete, rename, or manually merge the conflicted copy.
Scaling
Prototype: single region with whole-file uploads
Start with a web API, relational metadata database, object storage for complete files, and simple per-user folders. This proves auth, upload, download, listing, and sharing, but it wastes bandwidth on repeated whole-file uploads.
Growth: chunking, deduplication, and delta sync
Introduce client chunking, block hashes, upload sessions, content-addressed block storage, and a metadata commit step. Add a namespace journal and delta endpoint so clients sync changes instead of rescanning all files.
Large scale: sharded metadata and object-store data plane
Shard metadata by namespace or team, move blocks to a dedicated object-store data plane, partition the block index by hash, and deploy block upload workers independently from metadata services. Use CDN for downloads and queues for notifications and indexing.
Global scale: regional sync and exabyte storage
Place clients in the nearest region, keep metadata home regions for namespaces, replicate block objects across regions or fetch on demand, and serve downloads from regional object storage plus CDN. Use erasure coding and lifecycle tiers to control exabyte-scale cost.
Enterprise scale: governance, recovery, and tenant isolation
Add team namespaces, admin policy engines, audit logs, legal holds, malware scanning, data loss prevention, device trust, ransomware detection, and tenant-aware dedup boundaries. Isolate noisy tenants with quotas and per-namespace rate limits.
Bottlenecks & Optimizations
Metadata hot namespaces
A large shared folder or enterprise namespace can concentrate commits, list operations, and journal reads. Partition by namespace and, for very large namespaces, subpartition by folder or journal range. Use per-namespace write leaders, cache folder listings, and isolate team spaces that create hot spots.
Object-store bandwidth and upload spikes
Block uploads and downloads dominate bandwidth. Scale the Block Service separately, support direct-to-object-store uploads with signed URLs after authorization, use regional ingress, apply client backoff, and serve popular downloads through CDN.
Block index write amplification
Every uploaded block checks and possibly updates the block index. Batch missing-block checks, use partitioning by hash, keep idempotent conditional writes, and make reference counts approximate so commits do not synchronously update a hot counter.
Notification reconnect storms
Mobile networks, regional outages, or deployments can cause millions of clients to reconnect. Use jitter, exponential backoff, connection draining, regional shards, lightweight tokens, and periodic polling fallback instead of immediate reconnect loops.
Small-file metadata overhead
Many tiny files create more metadata and journal pressure than storage pressure. Batch client commits where safe, compress metadata pages, optimize folder listing indexes, and avoid forcing each small file through heavyweight global transactions.
Cold version retention cost
Versioning keeps old block references and can preserve blocks long after users stop reading them. Use lifecycle tiers, retention policies by plan, garbage collection after legal holds expire, and restore manifests that can read from cold storage asynchronously.
Failure Handling
Client crashes or loses network during upload
Upload sessions are resumable and expire after a bounded time. Already uploaded blocks remain content-addressed and idempotent. The file is not visible until the metadata commit succeeds, so partial uploads cannot create corrupt latest versions.
Object store write succeeds but metadata commit fails
The block remains unreferenced and safe. A background garbage collector later removes blocks that are not referenced by any committed version and are older than the upload-session grace period. The client retries commit or restarts the session.
Metadata database partition
Prefer correctness over accepting conflicting writes. Route a namespace to its metadata leader or quorum. If the leader is unavailable, pause commits for that namespace and continue serving cached reads or local client files where possible. Replay the journal after recovery.
Notification service outage
Clients fall back to periodic delta polling with exponential backoff. Metadata commits continue because notification fanout is asynchronous. When the service recovers, clients compare cursors and fetch any missed changes from the journal.
Corrupt or missing block detected
Block downloads verify hashes. If verification fails, the client retries another replica or region. Server-side integrity scanners compare object bytes to block hashes and repair from replicas. Metadata should never point to blocks that failed commit-time existence checks.
Regional outage
Route users to a healthy region for reads when replicated blocks and metadata are available. For namespaces homed in the failed region, allow read-only access from replicas if safe and queue writes or fail over leadership only through a controlled recovery process that preserves journal ordering.
Security
Authentication and authorization
Every metadata and block operation must authenticate the user or device and authorize access to the namespace, file, folder, or shared link. Signed block URLs should be short-lived and scoped to specific blocks and versions.
Encryption and key management
Use TLS for all traffic and encrypt blocks and metadata at rest. Large enterprises may require tenant-specific keys, key rotation, device revocation, and integration with customer-managed key systems.
Deduplication privacy
Global deduplication can reveal whether another user has a known file if APIs expose block-exists behavior too freely. Restrict missing-block checks to authenticated upload sessions, consider tenant-scoped dedup, and avoid returning sensitive existence signals.
Shared link controls
Shared links need unguessable tokens, optional passwords, expiration, download limits, domain restrictions, revocation, and audit logs. Revocation should invalidate cached download manifests and signed URLs quickly.
Malware and abuse scanning
Public links can distribute malware or illegal content. Scan uploads and popular shared downloads asynchronously, quarantine suspicious files, block known-bad hashes, and support abuse takedown workflows.
Ransomware and mass deletion protection
Detect unusual bulk renames, encryptions, deletes, and version churn. Alert users or admins, slow suspicious clients, and provide point-in-time restore using version history and namespace journals.
Tradeoffs
Pros
- +Block-level sync dramatically reduces bandwidth for edits to large files.
- +Content-addressable storage enables deduplication and strong integrity checks.
- +Separating metadata from block storage lets each plane scale independently.
- +Namespace journals give clients a clean convergence model after offline periods.
- +Immutable versions make restore, audit, and conflict handling easier to reason about.
Cons
- −Chunking and hashing add client CPU, battery, implementation, and debugging complexity.
- −Metadata correctness is harder than simple object upload because paths, versions, shares, and cursors interact.
- −Global deduplication improves cost but raises privacy and tenant-isolation concerns.
- −Notification infrastructure for millions of clients is operationally complex even though it is not the source of truth.
- −Version retention and restore windows increase storage cost and garbage-collection complexity.
Alternatives
Alternative one is whole-file storage. It is simple and works for small products, but re-uploading a 2 GB file for a tiny edit is unacceptable at scale.
Alternative two is file-system-level replication with a distributed consensus group per folder. It gives strong semantics for narrow workloads but is too heavy for hundreds of millions of consumer clients that are often offline.
Alternative three is application-specific collaboration, such as a document editor with operational transform or CRDTs. That can merge text edits in real time, but Dropbox must store arbitrary files where the service cannot understand the content safely.
When not to use this design
Do not use a generic Dropbox-style file sync system when the product requires real-time multi-user editing of structured documents, low-latency transactional databases, or strict POSIX filesystem semantics across machines. Those require collaboration engines, databases, or distributed filesystems with different consistency and locking models.
Follow-up Questions
Why split files into blocks instead of uploading whole files?
Blocks make sync bandwidth proportional to changed bytes rather than total file size. If a 2 GB video project changes one 4 MB block, the client can upload one block plus metadata instead of 2 GB. Blocks also enable deduplication across versions and users.
How do you know whether the server already has a block?
The client computes block hashes and sends the manifest during an upload session. The Block Service checks the block index by hash and returns only missing hashes. The server still verifies uploaded bytes against the hash before storing them.
How is a concurrent edit handled?
Each commit includes the client's base revision. If the current server revision still equals that base, the commit succeeds. If not, the client creates a conflicted copy or invokes a merge flow. The system should not silently overwrite arbitrary binary data.
What is the source of truth for remote changes?
The namespace delta journal is the source of truth. Notifications only wake clients and tell them to fetch deltas. If a notification is missed, the client later polls with its cursor and still converges.
How do you delete blocks safely when versions share them?
Treat blocks as immutable and reference-counted or mark-and-sweeped through version metadata. A block can be garbage-collected only after no retained file version, shared link, legal hold, or upload session references it.
How should shared folders affect sync?
A shared folder is usually a namespace or namespace mount with its own journal and ACLs. Members subscribe to that namespace, receive cursor notifications, and sync only changes they are permitted to see. Permission changes must also appear in the journal.
How do you recover from ransomware that encrypts many files?
Use anomaly detection on bulk rewrites and deletes, slow or quarantine suspicious clients, and provide point-in-time restore. Since every rewrite creates versions, the system can restore a namespace to a clean cursor before the attack if retention has not expired.
Company Variations
Amazon
Amazon interviewers may push on S3-style object durability, DynamoDB-style partitioning for block indexes, cost controls, lifecycle tiers, and failure isolation. Be ready to discuss direct uploads, conditional metadata commits, and how deduplication reduces exabyte storage spend.
Microsoft
Microsoft often frames this around OneDrive, SharePoint, Teams, enterprise identity, compliance, and Windows clients. Emphasize ACL inheritance, tenant isolation, audit logs, device management, customer keys, and conflict behavior for Office and non-Office files.
Google tends to probe global metadata consistency, tail latency, efficient sync at massive scale, and operational simplicity. Expect follow-ups on namespace journals, chunking strategy, cross-region replication, and the difference between Drive-like storage and Docs-like collaboration.
Meta
Meta may focus on media-heavy uploads, CDN downloads, privacy boundaries, abuse scanning, and high fanout notifications. Discuss hot shared content, photo and video deduplication, async pipelines, and resilient mobile sync.
Databricks
Databricks can angle the question toward large datasets, data lake storage, metadata catalogs, consistency of manifests, and cost-aware object storage. Explain why immutable blocks and version manifests resemble snapshot-based data systems.
Interview Tips
Lead with the core invariant: a file version is an immutable ordered list of block hashes plus metadata. Then draw the client-driven upload flow: chunk, hash, check missing blocks, upload missing blocks, commit metadata, publish journal, notify other clients. This communicates bandwidth efficiency and correctness before adding CDN, sharing, restore, and enterprise features.
When tradeoffs appear, tie them to the workload. Fixed blocks are simpler than content-defined chunks, global dedup saves storage but affects privacy, notifications improve latency but journals provide correctness, and conflict copies are safer than pretending the service can merge arbitrary bytes.
What interviewers expect
- ✓State assumptions and compute commits per second, logical ingest, unique block ingest, metadata growth, and fanout.
- ✓Draw separate metadata, block, object-store, CDN, and notification paths.
- ✓Explain chunking, content-addressed blocks, deduplication, and hash verification.
- ✓Use metadata commits with base revisions and namespace journals for convergence.
- ✓Discuss conflict copies, version restore, sharing permissions, and security controls.
- ✓Call out scaling and failure modes for clients, metadata shards, object storage, and notifications.
Common mistakes
- !Uploading whole files on every edit and ignoring block-level delta sync.
- !Mixing file bytes and metadata in one transactional database.
- !Using notifications as the source of truth instead of a replayable delta journal.
- !Silently applying last-writer-wins to arbitrary concurrent file edits.
- !Ignoring deduplication privacy and shared-link authorization.
Red flags
- ×No concrete capacity math for block storage, metadata growth, or notification fanout.
- ×No plan for offline clients and stale base revisions.
- ×No distinction between immutable blocks and mutable file metadata.
- ×No restore, versioning, or garbage-collection strategy.
- ×No answer for large shared folders or hot namespaces.
Revision Notes
- Dropbox-style sync separates metadata from block bytes. Metadata tracks paths, versions, permissions, and journals; object storage holds immutable content-addressed blocks.
- Clients chunk files, commonly around 4 MB per block, compute block hashes, and upload only missing blocks. This enables delta sync and deduplication.
- A file version is an immutable ordered list of block hashes plus size and metadata. Restoring a version creates a new commit pointing to an older block list.
- The Metadata Service must commit version records, latest pointers, and namespace journal entries atomically within a namespace.
- The namespace journal and cursor are the source of truth for sync. Notifications only wake clients so they can fetch deltas.
- Capacity is dominated by block storage and bandwidth: with 2B commits per day and 2 MB average changed payload, logical ingress is about 4 PB per day. At 40 percent unique physical storage, that is about 1.6 PB per day.
- Deduplication saves exabytes over time, but global dedup can leak information. Tenant-scoped or authorization-aware dedup is safer for enterprise workloads.
- Concurrent edits should compare against a base revision. For arbitrary files, create conflicted copies rather than silently overwriting.
- Large-scale bottlenecks include hot namespaces, object-store bandwidth, block index pressure, notification reconnect storms, and cold version retention.
- Security requires strong auth, ACLs, encrypted storage, short-lived signed URLs, shared-link controls, malware scanning, audit logs, and ransomware recovery.
Flashcards
Quiz
0/7 answered
1.What is the best reason to split files into blocks for Dropbox-style sync?
2.Which component is the source of truth for remote changes missed while a client was offline?
3.Why should the server verify a block hash after upload?
4.What should happen when a client commits based on a stale file revision?
5.Given 2B commits per day, what is the approximate average commit QPS?
6.What is a major privacy concern with global block deduplication?
7.Why is object storage a good fit for block payloads?
Cheat Sheet
Goal: design Dropbox, a cloud file sync and storage system with block-level delta sync, durable versions, sharing, and low-latency cross-device propagation.
Core idea: clients chunk files into blocks, compute hashes, upload only missing blocks, then commit metadata. A file version is an ordered list of immutable block hashes.
Data plane: Block Service verifies hashes, stores immutable blocks in object storage, records block hash to object location, and serves downloads through signed URLs and CDN.
Control plane: Metadata Service stores namespaces, folder tree, latest revisions, version history, shares, and namespace journals. Commits use base revisions to detect conflicts.
Sync flow: local change detected, chunk and hash, ask server for missing blocks, upload missing blocks, commit version, append journal, publish notification, remote clients fetch deltas and download missing blocks.
Capacity: with 2B commits per day and 2 MB average changed payload, logical ingress is about 4 PB per day. At 40 percent unique physical data, store about 1.6 PB per day before redundancy, reaching exabytes over time.
Consistency: notifications are best-effort wakeups. Cursors and namespace journals provide correctness and convergence for offline clients.
Conflicts: compare client base revision to latest revision. If stale, create a conflicted copy or explicit merge flow. Do not silently overwrite arbitrary files.
Storage optimization: fixed 4 MB chunks are simple; content-defined chunks improve insertion dedup but cost more CPU. Dedup saves storage, but respect tenant privacy.
Security: enforce auth and ACLs, encrypt at rest and in transit, scope signed URLs, secure shared links, scan malware, audit enterprise access, and support ransomware restore.
References
- BookDesigning Data-Intensive Applications — Martin Kleppmann
- BlogDropbox Tech Blog Infrastructure — Dropbox
- DocsAmazon S3 User Guide — Amazon Web Services
- PaperThe Tail at Scale — Jeffrey Dean and Luiz Andre Barroso