This gives away every stage. For a clean attempt, practise it first, then come back.
The short version
- Split files into chunks named by their fingerprint, and upload only the chunks the server doesn’t have.
- File bytes go straight to object storage. Our servers only handle the small metadata.
- A version is just a list of chunks, which makes history and de-duplication cheap.
- Each folder has a change log; devices remember how far they’ve read, and get a nudge when something changes.
- Commits say which version they started from, so conflicting edits become a conflicted copy, never lost work.
The 45 minutes
Before we start
Think about working on a presentation for a college project. You edit it on your laptop, your teammate edits it on theirs, and later you open it on your phone on the bus. Somehow everyone ends up with the latest version, and if two of you changed it at the same time, nothing disappears.
That’s file sync. The hard parts are: moving as little data as possible (files can be huge), keeping many devices up to date, including ones that were offline for days, and handling two people editing the same file without anyone losing work.
Same order as always: requirements, quick maths, data and API, a design that grows, then deep dives.
Minutes 0–5Requirements
Interviewer: Design a file sync service like Dropbox or Google Drive.
You: How many users, and how much does each store?
Interviewer: 50 million users, around 10 GB each on average.
You: How big can a single file get?
Interviewer: Up to 50 GB. Think video projects.
You: How many devices per person, and can they work offline?
Interviewer: Two or three devices each. Yes, offline edits should sync when the device reconnects.
You: What if two people edit the same file at the same time?
Interviewer: Never silently throw away anyone’s work.
You: Do we need sharing and version history?
Interviewer: Yes. Shared folders, and 30 days of history.
You: How quickly should changes reach other devices?
Interviewer: Within a few seconds when they’re online.
You: Live editing together, like Google Docs?
Interviewer: Out of scope.
Functional requirements
- Upload and download files and folders.
- Changes sync automatically to all of a user’s devices.
- Edits made offline sync when the device reconnects.
- Share folders with other people.
- Restore earlier versions for up to 30 days.
Out of scope: live co-editing, and syncing directly between devices on the same Wi-Fi.
Non-functional requirements
- Never lose a file.
- Never silently overwrite someone’s edits.
- Efficient: only upload the parts of a file that changed.
- Fast: changes reach other online devices within seconds.
- Big files work: a 50 GB upload survives dropped connections and resumes.
Minutes 5–10Back-of-the-envelope estimates
You: 50 million users at 10 GB each is 500 petabytes. That’s enormous, so storage cost matters as much as speed. Many files are identical across users, things like common installers and shared documents, so storing identical pieces once might save around 30%.
You: If each person changes about 10 files a day, that’s 500 million changes a day, roughly 6,000 a second.
You: If every change uploaded the whole file, at about 5 MB a file, that’s 2.5 petabytes of uploads a day. If we only upload the parts that changed, say 10% of a file, it’s about 250 TB.
Two conclusions. Storage is the biggest cost, so file bytes belong in object storage, stored once. And uploading only changed parts cuts traffic about ten times, so we need a way to know which parts changed.
Minutes 10–15Core entities and the API
Core entities
- Chunk: a piece of a file, about 4 MB, named by its fingerprint (a hash of its contents). Identical pieces have identical names.
- File and version: a file is a path in a folder. Each version is simply a list of chunk fingerprints.
- Namespace: a folder space that devices follow, like “my files” or a shared folder.
- Change log: an ordered list of changes in a namespace, each with a number.
- Device cursor: how far each device has read in each change log.
The API
/v1/uploads/checkBefore uploading, ask which chunks the server doesn’t have yet.
{ "chunks": ["a3f9…", "7c21…", "e044…"] }- 200
{ "missing": ["7c21…"], "upload_urls": { "7c21…": "https://storage.example/…?signature=…" } }
/v1/files/commitSave a new version as a list of chunks. Rejected if someone changed the file since you started.
{ "path": "/Trip/plan.docx", "chunks": ["a3f9…", "7c21…", "e044…"], "base_version": 41 }- 201
{ "version": 42 } - 409The file changed since version 41. Save yours as a conflicted copy.
/v1/changes?cursor=c_88301Everything that changed in my folders since this cursor.
- 200
{ "changes": [ { "path": "/Trip/plan.docx", "version": 42 } ], "cursor": "c_88305" }
Notice the upload URLs. They’re signed links straight to object storage, so the file bytes never pass through our own servers. Lesson 2.3 explains signed upload links.
Minutes 15–25The design, built up
Stage 1Upload whole files to a server
You: The simplest version: the laptop uploads each changed file to our server, which saves it on disk. Other devices ask “anything new?” every minute and download whole files.
It works for small files. But change one word in a 200 MB presentation and you upload 200 MB, then your phone downloads 200 MB. And one server’s disk can’t hold 500 petabytes.
Stage 2Chunks in object storage, metadata in a database
You: Two big changes. First, split every file into chunks of about 4 MB and fingerprint each one. Before uploading, ask the server which fingerprints it doesn’t have. Usually it’s just one or two. Upload only those, straight to object storage with signed links.
You: Second, separate file bytes from file facts. Chunks live in object storage. The facts, which files exist, which version is latest, and which chunks make up each version, live in a metadata database. Committing a new version is a small database write: “this file is now this list of chunks”.
Watch the difference for one small edit:
Because chunks are named by their content, two identical chunks are stored once, whoever uploaded them. That’s where the 30% saving comes from.
Stage 3Sync: a change log, cursors and nudges
You: Now other devices. Every commit adds an entry to that folder’s change log, with a number. Each device remembers how far it has read: its cursor.
You: Online devices keep one connection open to a notification service. When something changes, they get a tiny nudge: “something changed in this folder”. They then ask for changes since their cursor, download any chunks they’re missing, and rebuild the file.
You: An offline device does exactly the same when it reconnects, just with more changes to catch up on.
The nudge carries no data. If one is lost, the device simply catches up next time it checks. That keeps the notification service simple and makes lost messages harmless.
Stage 4Versions, conflicts and cleanup
You: Three last pieces. Conflicts: every commit says which version it started from. If someone else committed since then, the commit is rejected, and the device saves its version as a separate “conflicted copy” instead. Nothing is lost.
You: Versions: since a version is just a list of chunks, keeping 30 days of history is cheap.
You: Cleanup: a background job removes versions older than 30 days, and deletes chunks only when no version uses them any more.
Checking the design against the requirements
| Requirement | Where the design handles it |
|---|---|
| Upload and download | Chunks straight to and from object storage with signed links |
| Sync across devices | Change log per folder, cursors, and nudges |
| Offline edits | Devices commit and catch up using their cursor when back online |
| Share folders | A shared folder is its own namespace that each member’s devices follow |
| 30 days of versions | A version is a list of chunks; cleanup after 30 days |
| Never lose a file | Object storage keeps multiple copies; chunks deleted only when unused |
| Never silently overwrite | Commits check their base version; conflicts become copies |
| Only upload what changed | Chunks named by fingerprint; only missing ones are sent |
| Fast | Nudges over open connections, then a small change-log read |
| Big files resume | Chunks already uploaded are never sent again |
Deep diveUploading only what changed
Interviewer: How exactly do you avoid re-uploading a whole file?
Bad solutionUpload the whole file every time
Simple, and wasteful. A small change to a large file costs the whole file in both directions, for every device.
Good solutionFixed-size chunks
Split files into 4 MB chunks and fingerprint each. Only chunks with new fingerprints are uploaded. Dropbox has described using 4 MB blocks this way. But there’s a catch: insert a few bytes near the start of a file, and every chunk boundary after that shifts, so every later chunk looks new.
Great solutionChunk boundaries chosen by the content
Instead of cutting every 4 MB exactly, cut where the content itself matches a pattern, found by sliding a small window over the data and hashing it as you go (a rolling hash). An insertion then only changes the chunks around it, and later boundaries line up again, so they keep their old fingerprints. It’s more complex, but much better for files that get edited in the middle.
Deep diveTwo people edit the same file
Interviewer: You and a teammate both edit plan.docx on a train, offline. You both reconnect. What happens?
Bad solutionLast write wins
Whoever syncs second replaces the first person’s version. Someone’s work vanishes without a word, the one thing the interviewer said must never happen.
Good solutionReject commits that started from an old version
Each commit includes the version it was based on. The first person’s commit, based on version 41, succeeds and becomes version 42. The second person’s commit is also based on 41, but the file is now at 42, so it’s rejected.
Great solutionReject, then keep both as a conflicted copy
The second device doesn’t just fail. It saves its version under a new name, like “plan (Meera’s conflicted copy).docx”, and syncs that. Both versions now exist everywhere, nothing is lost, and the people involved decide how to merge. This is what Dropbox does. Merging automatically would require understanding every file format, which is why live co-editing is a different product.
Deep diveCatching up after a week offline
Interviewer: A laptop has been off for a week. How does it catch up?
You: It still has its cursor for each folder, the number of the last change it saw. It asks for everything after that number, applies the changes in order, and downloads whatever chunks it doesn’t already have. If it also made changes offline, it commits them, and any conflicts become conflicted copies as usual.
You: If it’s been gone so long that the old part of the change log has been cleaned up, it falls back to comparing its full file list with the server’s. Slower, but it only happens rarely.
Deep diveStoring identical files once
Interviewer: A million users upload the same 1 GB installer. Do you store it a million times?
You: No. Its chunks have the same fingerprints for everyone, so they’re stored once, and each chunk keeps a count of how many versions use it.
You: There’s a privacy catch worth mentioning. If the app skips uploading chunks the server already has, someone can learn whether anyone has a particular file, just by noticing the upload was instant. So many services only remove duplicates within one person’s or one team’s files, not across everyone.
Deep diveDeleting safely
Interviewer: How do deletes and old versions get cleaned up without losing data?
You: Deleting a file just marks it deleted. It stays restorable for 30 days.
You: A background job removes versions older than 30 days. Each removed version lowers the count on its chunks, and a chunk is only deleted from storage when its count reaches zero.
You: The dangerous moment is a race: a new upload starts using a chunk at the same moment the cleanup job decides it’s unused. So cleanup waits a while after a chunk’s count reaches zero and checks again before deleting. Losing data is far worse than keeping a chunk a day longer.
The complete architecture
Here’s everything together: the full design from the last stage, with every part we added along the way. If you only remember one picture from this question, make it this one.
How one request travels through it:
- You save a file. The sync client on your laptop splits it into chunks of about 4 MB and works out a fingerprint (hash) of each.
- It asks the metadata service which of those chunks the server doesn’t have yet. Usually only one or two are new.
- It uploads only the missing chunks, straight to object storage, using signed upload links. Our servers never carry the file bytes.
- It commits the new version: this file is now this list of chunks, based on version 41. If someone else changed the file since 41, the commit is rejected and the client saves a conflicted copy instead.
- The commit adds an entry to the folder’s change log, and the notification service nudges your other devices over their open connections.
- Each device asks for changes since its cursor, downloads any chunks it’s missing, and rebuilds the file. Offline devices do the same when they reconnect.
How this answer gets scored
Interviewers don’t tick boxes, but their notes on this question tend to land on the same few moments. Here’s what each one sounds like from the other side of the table.
| Moment | What earns credit | What costs you |
|---|---|---|
| The first five minutes | Asking about conflicts, offline edits and file sizes | Asking only how many users |
| Uploads | Chunks named by fingerprint, only missing ones sent | Re-uploading whole files |
| Where bytes go | Straight to object storage with signed links | Streaming every file through your own servers |
| Sync | A change log, cursors and nudges | Every device polling constantly |
| Conflicts | Base versions and conflicted copies | Last write wins |
| Cleanup | Counting chunk use, deleting carefully | Deleting chunks as soon as a version is removed |
What the left column has in common: every choice points back to a requirement or a number from earlier. If you can say where each box came from, the interviewer will notice.
Stay in the loop
Get new problems and walkthroughs by email
One short email when something new is published: a deep-dive walkthrough, an LLD problem, or a real outage retold. No spam, unsubscribe any time.