A file changes on one laptop and must appear on three others, one of which is offline. What travels over the network, and what happens when two of them edited it?
In file sync, the file itself does not travel. Changed content-hashed chunks go to a block store, then a small metadata commit names the version it replaced. Other laptops pull the new manifest and the chunks they lack. A concurrent edit fails that commit and becomes a conflicted copy, never a silent overwrite.
6 min readUpdated 2026-10-09
0
Answer
Short answer
The file itself does not travel. Good file sync breaks each file into content-hashed chunks and uploads only the chunks the server lacks. It then commits a small metadata record listing the chunk hashes and naming the version it replaced. The other laptops learn a new version exists, fetch the manifest, and download only the chunks they are missing. If two laptops edited from the same base, the second commit is refused and its edit is kept as a conflicted copy rather than thrown away.
This page is about file sync mechanics. For reading what the interviewer wants from a deliberately vague "let users share files" brief, see the interviewer psychology guide.
Was this answer helpful?
Likely follow-ups
→Your laptops sync peer-to-peer on the same office network with no server in the loop. What replaces the server's version number, and what does that cost?
→Deduplication is global across all accounts. What can a client that knows only a chunk's hash now do that it should not?
→One laptop deleted the folder while the offline one edited a file inside it. What should each of the four machines end up with?
→A user saves a 40 GB virtual machine image every few minutes. Which part of your design struggles first?
A file sync design has two kinds of data, and they want different storage.
The block path holds file content as immutable chunks, each named by a hash of its bytes such as SHA-256. Because the name is derived from the content, a chunk never changes. It can be cached anywhere, retried safely and stored once even if a hundred files contain it. This is content-addressed storage, and it is where the bytes and the bandwidth go.
The metadata path holds the namespace: which paths exist, and for each file an ordered list of chunk hashes plus a version number. It is small, it must be strongly consistent, and every change to it needs an order. This is where correctness lives, and it is where the conflict question gets answered.
Keeping them apart lets each scale on its own terms. Blocks scale like object storage. Metadata scales like a database partitioned by account or shared folder, with a change log per partition that devices read from.
What chunking saves in file sync, and the insertion problem
Suppose a 1 GB file is split into 4 MB chunks, giving 256 of them. The user changes one paragraph in place. One chunk's hash changes, so one chunk uploads. That is the whole point of chunking.
Now the user inserts a single byte near the start instead. With fixed-size chunks, every boundary after the insertion shifts by one byte, so nearly every chunk after it hashes differently. The client re-uploads almost the whole gigabyte for a one-byte change.
Content-defined chunking fixes this. A rolling hash slides over the bytes, and a chunk boundary falls wherever the hash matches a chosen pattern, so boundaries depend on local content rather than on offsets. After an insertion, the boundaries re-align within a chunk or two, and only those chunks change. The cost is variable chunk sizes and more CPU on the client. A candidate who brings up the insertion case without being asked has thought about real files rather than the happy path.
One edit, step by step
Laptop A saves the file. Its client works out which chunks changed and asks the block store which of those hashes it already holds. It uploads the missing ones. Only then does it commit new metadata, and that commit says "this replaces version 7 of this file".
Loading diagram…
Look at the order. Chunks land before the metadata commit, so no laptop can ever see a manifest that points at bytes that do not exist yet. Laptop B and the third online laptop hold a long-lived connection or poll. When told the namespace changed, each asks for every change since its own cursor in the change log, then downloads only the chunks absent from its local cache.
The offline laptop comes back
The fourth laptop was offline for two days, and someone edited the same file on it. On reconnect it does two things.
First, it pulls. It presents its cursor and receives every metadata change since, then fetches the chunks for files it did not touch. Second, it pushes its own local edits. Each one is a commit naming the version the laptop last saw, which for this file is version 7.
The server is now at version 8. The commit's base no longer matches, so the server refuses it. That refusal is the conflict detection, and it costs one comparison.
Every commit has to say what it replaced
The weak answer settles the two edits by modification time, or simply accepts the last upload. Both lose data silently. The offline laptop's clock may be wrong, and "last upload" means "whichever machine found a network last", which says nothing about which edit the user cares about. The edit made two days ago on the plane overwrites this morning's work, and nobody is told.
The strong answer makes every metadata commit conditional on its base version, a compare-and-set on the file's version. A stale base is refused, never applied. Without that, there is nothing to detect a conflict with.
Once detected, the conflict usually cannot be merged automatically, because the sync layer does not understand a spreadsheet or a Photoshop file. The safe resolution keeps both. Version 8 stays at the original path, and the offline edit is saved next to it as a conflicted copy named with the device and date. No edit is lost, and the person who understands the content chooses.
A delete racing an edit needs the same care. If a delete is a tombstone with its own version, the edit's commit sees the conflict. The sensible default then keeps the edited file, because bringing back something deleted is recoverable and losing an edit is not. The general theory of detecting and resolving concurrent offline writes is covered in two offline edits reconnect.
When you need version vectors
With one central metadata service, a per-file version number is enough, because the server puts every commit in a single order. Version vectors become necessary when laptops sync directly with each other, for example over a local network with no server involved. Then no single party orders the writes, and each device must carry a counter per writer to tell "newer" apart from "concurrent". Saying which of these situations you are designing for, rather than reaching for version vectors by reflex, is a senior signal.
Detecting the change in the first place
Every file sync client has to notice local edits before it can send anything. It learns about local edits from the operating system's file watcher, such as inotify on Linux, FSEvents on macOS or ReadDirectoryChangesW on Windows. These events can be dropped, merged or delivered while an application is still writing. So treat them as hints. Keep a local index of path, size, modification time and chunk hashes, rescan against it periodically, and wait for writes to settle before hashing.
The same index stops a feedback loop. When the client writes a file it has just downloaded, the watcher fires. If the new hashes match what the index already records for that version, the client must not upload it back.
Chunks make sync cheap and the version check makes it safe. Content-addressed chunks decide how little travels, and a commit that names the version it replaced decides whether a concurrent edit is caught or silently lost.