File Storage & Sync: Interview Perspective
How to approach 'Design Dropbox / Google Drive' in a system design interview — from opening moves to final architecture, plus a full bank of realistic follow-up questions across scope, upload, metadata, synchronization, delta sync, conflicts, sharing, scaling, versioning/GC, CDN/download, and failure curveballs.
Opening Move
Start by clarifying the scope. 'Design Dropbox' is broad — the interviewer wants to see you narrow it to the most important problems.
Say something like: 'File storage and sync has several distinct challenges — reliable upload of large files, durable storage, multi-device synchronization, and access control. I'll start with requirements and scale, then build the architecture from first principles, starting simple and evolving as we hit bottlenecks. Should I focus on any particular area?'
Requirements & Scale
Spend 2–3 minutes on requirements. This is where you demonstrate that you think about the problem before jumping to solutions.
Functional requirements to state
Upload files (including very large files, resumably). Download from any device. Sync changes across devices automatically, including offline edits and conflicts. Share files with access control. File versioning and restore. Folder hierarchy and operations.
Non-functional requirements to state
High durability with an appropriate recovery/backup strategy (avoid promising an absolute 'never lost'). High availability. Efficient bandwidth (sync only what changed, where practical). Secure access on every operation. Bounded sync freshness rather than instant.
Scale to estimate
~500M users, 100M DAU. ~200M uploads/day. Average file 5 MB, up to 50 GB. ~1 PB new data/day. 5:1 read-to-write ratio. 100M devices syncing. State these as illustrative assumptions that drive the design, not as facts about any real product.
API Before Architecture
Define the key APIs before drawing boxes. This shows the interviewer you think about the system from the client's perspective.
The essential endpoints: POST /files (create record, get upload URL, idempotency-key protected), PUT /files/{id}/upload (initiate upload → presigned URL / multipart session), POST /files/{id}/complete (finalize upload, idempotent), GET /files/{id} (metadata), GET /files/{id}/download (auth → presigned download URL), PATCH /files/{id} (rename/move with a version precondition), GET /sync/changes?cursor=... (durable delta since last checkpoint).
Building the Architecture
Start simple. Show the bottleneck. Then introduce the right component — and be precise about why, not just what.
Start simple
Draw: User → File API → Database + Local Storage. Say: 'This works for small files and a few users. Let me show where it breaks — and be specific about the actual bottlenecks, not just a vague CPU number.'
Introduce metadata/storage separation
Say: 'File bytes and metadata are different workloads. Object storage is purpose-built for large binary blobs at this scale — durable, cheap per GB, independently scalable. The database stores queryable metadata. For this workload and scale, storing multi-GB blobs in a relational database isn't a good fit — though it can be a reasonable choice for small files in other systems.'
Introduce direct upload
Say: 'The application server should orchestrate, not proxy bytes, in the normal large-file path. The client calls the File Service for a presigned URL, then uploads directly to object storage. This removes byte-proxying load from the application tier — I won't quote an exact CPU number, but the mechanism is what matters: bandwidth and connection pressure move off the app tier.'
Introduce chunked upload
Say: 'A 10 GB file as one PUT still fails completely on a network drop. With chunked upload, each chunk — sized based on provider limits, network conditions and file size, not a fixed universal number — has its own presigned URL and acknowledgment. If one chunk fails, only that chunk retries.'
Important Deep Dives
The interviewer will pick one area to go deep. Be ready for any of these.
Upload flow deep dive
Walk through the full flow: POST /files creates metadata (CREATED) → upload initiation returns presigned URL(s)/session → client uploads directly to object storage → completion call verifies integrity and only then flips lifecycle state to AVAILABLE. Mention session expiration, orphan cleanup, and that completion must be idempotent. Read deeper: Architecture Deep Dive → Multipart Upload State Machine and Metadata/Object Consistency.
Sync deep dive
Explain local change discovery (filesystem watch + periodic reconciliation), remote change discovery via a durable cursor-based change log (push is just a hint), the sync client's own local state machine, and delta transfer as a distinct algorithm from whole-file hashing. Mention offline queuing and cursor-retention fallback to full resync. Read deeper: Architecture Deep Dive → Sync Client State Machine, Sync Change Log & Cursor Semantics, Delta Sync Algorithms.
Conflict resolution deep dive
Explain the parent-version model: every version records its parent; the server accepts a mutation only if its declared base version is still current. Two versions with the same parent = conflict. Default: preserve both as conflict copies. Alternatives: last-write-wins (simple but lossy), three-way merge (works for text, not binary, and is a product-policy choice). Read deeper: Architecture Deep Dive → Conflict Detection and Optimistic Concurrency.
Access control deep dive
Auth service checks ACL on every file operation. Presigned URLs are only generated after authorization passes, and are treated as bearer capabilities, not identity-bound credentials — revoking access does not retroactively invalidate an already-issued URL. Folder sharing introduces inherited permissions. Read deeper: Architecture Deep Dive → Sharing, ACLs and Revocation.
Full Question & Follow-Up Bank
Scope & Requirements
Are we designing storage only, or storage plus multi-device sync?
Clarify scope explicitly — sync, conflict resolution, and offline handling are a substantially different (and larger) problem than upload/download/storage alone. State which you're covering and why, rather than assuming.
- What's the maximum file size we need to support? — Drives chunking strategy and part-count/size trade-offs — see Trade-offs & Decisions → Chunk/Part Size Selection.
- Do we need offline editing? — If yes, the sync client state machine and conflict handling become first-class, not optional — see Architecture Deep Dive → Sync Client State Machine.
Do we need a multi-region requirement, or is single-region acceptable for this design?
Push back on scope creep toward active-active global metadata unless the interviewer specifically asks for it — a bounded single-region-primary-with-DR-failover story is defensible for a foundations design.
- What availability vs durability trade-off matters more here? — These are different properties — durability is about not losing data, availability is about being reachable; see Architecture Deep Dive → Disaster Recovery and Multi-Region.
File Upload
Why direct-to-object-storage instead of proxying through the application?
At scale, proxying bytes through the application tier consumes bandwidth, holds long-lived connections, and couples data-transfer availability to control-plane availability. Direct upload via a presigned URL keeps the application tier lightweight — orchestration and authorization only.
- How do presigned URLs actually work? — See Architecture Deep Dive → Presigned URL Security — emphasize bearer-capability semantics, not 'non-transferable.'
- What if the URL expires mid-upload? — See Failure & Scale → Presigned URL Expiry — differentiate URL expiry, session expiry, and credential/policy changes.
How do you resume a 50 GB upload that failed at 90%?
Chunked/multipart upload with a durable session: the client (or service, where supported) reconciles which parts are actually confirmed in storage, then uploads only the missing parts before an idempotent completion call.
- How do you choose part size? — Provider limits, part-count ceiling, file size, network conditions, client memory, and parallelism — not a fixed 5–10MB rule; see Trade-offs & Decisions → Chunk/Part Size Selection.
- What if the object upload succeeds but the metadata commit fails? — Central consistency failure — see Architecture Deep Dive → Metadata/Object Consistency and Failure & Scale Scenarios → Upload Completes in Storage but Metadata Commit Fails.
How do you verify upload integrity end-to-end?
Distinguish transport (TLS), per-part checksum, whole-object checksum, and application content hash. The completion step should verify the assembled object against an expected checksum before marking it AVAILABLE.
- Is ETag always a reliable integrity checksum? — No — ETag semantics vary by provider, encryption mode, and multipart behavior; don't assume ETag == MD5. See Architecture Deep Dive → End-to-End Data Integrity.
Metadata vs Bytes
Why separate metadata from file bytes instead of storing everything in one system?
They're different workloads: metadata needs queryable, relational, frequently-updated small records; bytes need durable, cheap, large-object storage with independent scaling. For this design's scale, this separation is the foundational decision — but note it's a workload-driven choice, not a claim that databases can never store any blobs.
- How do you keep the two systems consistent? — There's no ordinary atomic transaction spanning both — see Architecture Deep Dive → Metadata/Object Consistency for the verify-then-publish state machine.
Why use a stable file_id instead of the file's path as its identity?
Rename and move are extremely common operations; if identity were the path, every rename would be an identity change. A stable file_id lets rename/move be cheap metadata mutations, and lets sync clients recognize 'same file, new name' instead of treating it as delete-plus-create.
- How does that affect folder listing and uniqueness? — See Architecture Deep Dive → Metadata Model, Namespace & Folder Hierarchy — listing by parent_folder_id, optional (parent_folder_id, normalized_name) uniqueness.
Synchronization
How does a device detect that it made a local change?
A filesystem watcher (inotify/FSEvents/ReadDirectoryChanges-style) plus a periodic full reconciliation scan as a safety net against missed events.
How does a device discover changes made on other devices?
It calls a durable, cursor-based change endpoint. Push notifications are only a wake-up hint that something changed — the durable change log, not the push payload, is the source of truth.
- Why use a cursor instead of a timestamp? — Avoids clock-skew bugs between devices and the server; a cursor represents 'all changes up to X have been processed.'
- What if the device missed the push notification entirely? — See Failure & Scale → Sync Notification Service Down — reconnect/periodic polling catches up regardless.
What happens if a device is offline for months?
If it's offline longer than the server retains change history, incremental cursor replay is no longer possible. The fallback is a full metadata snapshot, comparison against local state, reconciliation of any pending local operations, and establishing a fresh cursor.
- How do you handle duplicate or out-of-order sync events? — Operation IDs and version checks make replay idempotent and order-safe — see Architecture Deep Dive → Ordering and Idempotency.
Delta Sync
Does a whole-file hash tell you which bytes changed?
No. It only tells you that content changed. Identifying which bytes changed requires block-level signatures or a content-defined-chunking/rolling-checksum approach.
- When is delta sync not worth it? — Compressed, encrypted, or otherwise binary-dense formats can have a small logical edit that changes much of the byte representation — whole-file replacement may be simpler and equally effective.
Compare whole-file replacement, fixed blocks, and rolling/content-defined chunking.
Whole-file is simplest and best for small/incompressible-delta files. Fixed blocks are simple but broken by insertions shifting subsequent boundaries. Rolling checksums (rsync-style) find matching regions despite shifted offsets, at the cost of CPU and chunk-index metadata.
Conflict Resolution
Two devices edit the same file offline — what happens when both reconnect?
Both submit a mutation based on the same parent version. The server detects the version fork (not by timestamp) and, by default, preserves both as conflict copies rather than silently picking a winner.
- Why not just use timestamps / last-write-wins? — Clock skew between devices makes timestamp-based ordering unreliable, and last-write-wins silently discards one side's work — that's a product policy choice, not a distributed-systems requirement.
- When is three-way merge possible? — For mergeable text formats using the common ancestor version — not for binary files, and not a substitute for real-time collaborative editing (CRDT/OT), which is out of scope here.
What if one device deletes a file while another edits it offline?
This is a delete/edit race. Tombstone (soft-delete) semantics let the reconnecting device learn the file was deleted rather than silently re-uploading its edit as a brand-new file. Product policy then decides: restore as conflict copy, reject as stale, or create a recovered file.
Sharing & Security
How do you enforce viewer vs editor access?
An ACL check on every file operation, backed by a permissions table recording owner, direct shares, and folder-inherited permissions with defined override rules.
What if an ACL is revoked after a signed download URL was already issued?
The already-issued URL remains usable until it expires — revocation is not retroactive for a plain bearer-capability URL. Mitigate with short TTLs, and use a stricter token-validation/proxy path only if instant revocation is a hard requirement.
- Can a signed URL be shared/forwarded by the recipient? — Generally yes — treat it as a bearer capability unless the design adds an explicit additional binding mechanism. Don't claim it's non-transferable.
Should authorization fail open or fail closed when current permission state can't be determined?
Fail closed. Serving a stale cached 'allowed' answer during a metadata outage risks honoring a permission that has since been revoked.
Metadata Scaling
SQL or NoSQL for metadata, and why?
Either can work; avoid caricatures like 'NoSQL means no joins' or 'SQL means vertical-only.' Compare on transaction model, access patterns, secondary-index support, consistency needs for ACL enforcement, and sharing-query shape. A relational store is a reasonable illustrative choice given this design's join-heavy sharing queries.
How would you shard the metadata store, and what breaks for 'files shared with me'?
Owner/user sharding gives good 'my files' locality but a large tenant can become a hot shard, and cross-owner sharing queries need a secondary recipient-oriented index rather than scanning every shard.
- How do you handle a hugely oversized tenant or a huge shared folder? — Paginated listings, asynchronous fan-out, and per-tenant fairness limits — see Failure & Scale Scenarios → Hot User / Huge Shared Folder.
Versioning, Deletion & GC
How do you store and retain file versions?
One immutable object per committed version; current metadata points to the current version. Retention (keep-all, time/count/quota-based) is a separate policy layered on top — don't conflate the application's version concept with a storage provider's native object versioning feature.
How do you clean up orphaned uploads and prevent GC from deleting referenced data?
Never delete a blob solely because one transient metadata lookup says it's unreferenced. Use soft-delete with a grace period, idempotent GC jobs, and periodic audit/reconciliation — GC bugs here are one of the few failure modes that can cause genuine permanent data loss.
CDN & Download
Should private files be served through a CDN?
It's workload-dependent — public/shared immutable content benefits most from caching; private/high-cardinality files may see little reuse. If private content is CDN-delivered at all, it needs its own signed-URL/cookie authorization design at the edge — an ordinary object-storage presigned URL doesn't automatically become CDN-backed.
- How do immutable/versioned object keys help? — A new version gets a new key/URL, sidestepping most cache-invalidation problems instead of relying solely on purging a mutable URL.
How do you support resumable downloads of large files?
HTTP range requests — resume from the last received byte, fetch partial ranges, or support streaming/preview without downloading the whole object first.
Failure Curveballs
What if object storage is temporarily down?
Bounded retry with backoff/jitter; metadata browsing can remain available; in-progress multipart uploads need explicit reconciliation on recovery, not an assumption of automatic resume.
What if the metadata primary goes down?
Fail closed for authorization-sensitive operations; don't rely on an in-memory application write queue as a durable recovery mechanism; failover time is deployment-specific, not a fixed number.
What if the upload completes in storage but the metadata commit fails?
This is the central metadata/object consistency failure. Idempotent completion plus a reconciliation job that verifies storage state and safely commits AVAILABLE (or garbage-collects a truly orphaned object after a grace period) is the answer.
What if the sync push/notification service goes down?
Push is an optimization, not the source of truth — clients fall back to cursor-based polling on reconnect and still catch up, just with higher latency.
What Makes a Strong Answer
The difference between a good and great answer is not the final architecture — it's the reasoning that builds it.
- Lead with requirements and scale — show you think before you draw, and label assumptions as illustrative
- Define APIs before internal architecture — think from the client's perspective, including idempotency and version preconditions
- Build from simple to complex — each component solves a visible problem, without inventing precision such as fixed CPU percentages or universal chunk sizes
- Separate file bytes from metadata — different workloads, different tools, with an explicit consistency-reconciliation story between them
- The application orchestrates — it never proxies large file bytes in the normal path
- Presigned URLs are bearer capabilities, not non-transferable, identity-bound credentials
- Sync uses a durable cursor-based change log as truth, with push as a hint and delta transfer as a distinct algorithm from whole-file hashing
- Conflicts are detected by version lineage — not timestamps
- Every trade-off has alternatives — explain why you chose yours and state its limits instead of claiming universal guarantees