Get Started

Build a Dropbox-style file sync engine

Keep two folders, standing in for two devices, perfectly in step. Build a two-way sync engine in the Python standard library that fingerprints every file by its contents, works out the smallest set of changes, copies only what is needed, propagates deletes without resurrecting them, and handles the genuinely hard part: when both sides edited the same file, it keeps both versions instead of silently losing one. You will understand sync indexes, content hashing, three-way compare and why naive mtime sync corrupts data.

107 minAdvancedTools: FreeStep 1 free
Tested 12 Oct 2026 · Python 3.13.5, standard library only (hashlib, os, json), Windows 11. Tests run with pytest 9.1.1 fetched by uv 0.11.9.
A working two-way sync engine in about 260 lines of standard-library Python: content hashing, a sync index, a three-way compare, delete propagation, conflict handling and atomic writes
A clear grasp of the hard partswhy modification-time sync corrupts data, how the index tells a real delete from a file one side never saw, and how a conflict is kept rather than lost
Ten passing tests and a command-line tool with a dry-run, ready to point at two real folders
Before you start
01/08Why sync is harder than copy0 done
STEP 01 of 08~12 min

Why sync is harder than copy

Copying is one-way and forgetful. Sync has to remember what the two sides last agreed on, or it cannot tell an edit from a delete, or a delete from a file it has never seen. Seeing the finished engine run makes the shape of the problem clear.

  1. Copying one folder over another is easy: overwrite everything, done. Sync is harder because changes happen on both sides, and the engine has to work out *what changed* and *who changed it* before it touches a single file. Three questions trip up every naive attempt:

    • A file is in A but not in B. Did someone add it in A (copy it to B), or delete it in B (so remove it from A too)? The two need opposite actions, and the file alone cannot tell you which.
    • A file differs between A and B. Which side is newer? Using the clock to decide is where data gets lost, as you will see in step 3.
    • Both sides edited the same file since they last agreed. There is no right answer that keeps only one. Pick a winner and someone's work is gone.
  2. The answer to all three is a sync index: a small record of the state both sides last agreed on, kept between runs. With it, the engine does a three-way compare for every file (the index as the common base, the file in A, the file in B) and the right action falls out. Without it, sync is guessing.

  3. Get the kit. Every file is in /learn/build-a-file-sync-engine: syncengine.py (the engine), demo.py (the scenarios), sync.py (a command-line tool), test_syncengine.py and requirements.txt. Put them together in one folder, for example file-sync in your Documents, and open a terminal there.

  4. The whole engine is standard-library Python, so you can run the scenarios straight away. demo.py builds two folders in a throwaway sandbox, puts files in them, and runs four scenarios, printing the real fingerprints and the decisions the engine makes:

    In the file-sync folder
    python demo.py
  5. The first scenario is the easy one: B is empty, A has three files, so every file is an add to B. Note the twelve-character fingerprints; those are the start of each file's content hash, which the next steps explain:

    Output
    ======================================================================
    1. Initial sync: make B match A
    ======================================================================
    
      A before:
        notes.txt                          ef1821c82589  11 bytes
        photos/cat.txt                     93eca2959c10  23 bytes
        todo.md                            c08a755ff142  11 bytes
    
      B before:
        (empty)
    
      Sync report:
        ADD       B    notes.txt                          ef1821c82589 (11 bytes)
        ADD       B    photos/cat.txt                     93eca2959c10 (23 bytes)
        ADD       B    todo.md                            c08a755ff142 (11 bytes)
        (0 file(s) already in sync)
    
      B after:
        notes.txt                          ef1821c82589  11 bytes
        photos/cat.txt                     93eca2959c10  23 bytes
        todo.md                            c08a755ff142  11 bytes
  6. The run keeps going through three more scenarios (an edit, an add-and-delete, and a conflict), which the rest of the lesson takes apart one at a time. For now you have seen the destination: a report of add / update / delete / conflict decisions, each with the fingerprint that justifies it.

    TipRun python demo.py --keep and the sandbox folder stays behind, with folders A and B and the index.json it built, so you can open them and look. Without --keep the sandbox is removed at the end, so every run starts clean.
✓
Checkpointpython demo.py prints four numbered scenarios and ends with Sandbox removed. Scenario 1 shows three ADD B lines.
If it breaks'python' is not recognised, or it opens the Microsoft Store + 2 more
'python' is not recognised, or it opens the Microsoft Store
Python isn't installed or isn't on your PATH. Install it as in Install anything from GitHub, safely, then close the terminal and open a new one. On Windows, try py demo.py instead of python demo.py.
'ModuleNotFoundError: No module named syncengine'
demo.py imports syncengine.py, so the two must sit in the same folder, and you must run the command from that folder. Check with dir (Windows) or ls (Mac and Linux) that both files are there.
'can't open file demo.py'
You're in the wrong folder. cd into the folder where you saved the kit files first.
Still stuck? Ask the community
Next mission · Advanced buildsBuild an RC car that learns to drive itself by watching you
→