Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes
Sponsored Reserved space — layout preview until AdSense is connected

How to Sync Two Folders in Python (Lightweight Backup)

A Python script that synchronizes a source folder to a destination folder, copying new or updated files and removing files that no longer exist in the source.

Medium Python 3.6+ Jun 28, 2026 Files & data 3 views 0 copies

Python code

41 lines
Python 3.6+
import os
import shutil
import sys
from pathlib import Path

def sync_folders(src: Path, dst: Path):
    """Sync src folder to dst folder, copying missing/updated files."""
    dst.mkdir(parents=True, exist_ok=True)

    for src_path in src.rglob("*"):
        relative = src_path.relative_to(src)
        dst_path = dst / relative

        if src_path.is_dir():
            dst_path.mkdir(parents=True, exist_ok=True)
        elif src_path.is_file():
            if not dst_path.exists() or src_path.stat().st_mtime > dst_path.stat().st_mtime:
                shutil.copy2(src_path, dst_path)
                print(f"Copied: {relative}")

    # Remove files in dst not present in src
    for dst_path in dst.rglob("*"):
        relative = dst_path.relative_to(dst)
        src_path = src / relative
        if not src_path.exists():
            if dst_path.is_dir():
                shutil.rmtree(dst_path)
            else:
                dst_path.unlink()
            print(f"Removed: {relative}")

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Usage: python sync_folders.py <source> <destination>")
        sys.exit(1)
    source = Path(sys.argv[1])
    destination = Path(sys.argv[2])
    if not source.is_dir():
        print("Source must be an existing directory.")
        sys.exit(1)
    sync_folders(source, destination)

Output

stdout
Copied: new_file.txt
Copied: subfolder/updated_data.csv
Removed: old_backup.log
Removed: temp_cache

How it works

The script uses Path.rglob from pathlib to recursively walk both source and destination trees, preserving the relative path structure. For each file in the source, it checks whether the destination copy is missing or outdated by comparing modification times via stat().st_mtime. shutil.copy2 copies the file while preserving metadata (like timestamps). After the copy phase, the reverse scan removes destination files and folders that have no counterpart in the source, using shutil.rmtree for directories and unlink for files. The __main__ guard validates command-line arguments and ensures the source exists before invoking the sync logic.

Common mistakes

  • Forgetting to call `mkdir(parents=True, exist_ok=True)` before writing files, which raises a FileNotFoundError.
  • Using `shutil.copy` instead of `shutil.copy2`, losing original file metadata like modification time.
  • Not skipping directories when comparing modification times (`.st_mtime` on a directory gives a meaningless value and varies across OSes).
  • Calling `shutil.rmtree` on a symlink or file accidentally, causing data loss in the destination.

Variations

  1. Use `filecmp.cmp` instead of modification time for byte‑level accuracy, at the cost of speed.
  2. Add a `dry_run` parameter to print actions without actually copying or deleting.
  3. Use `hashlib` to compare file hashes for high integrity checks on large binary files.

Real-world use cases

  • Automating backups of a project's assets folder to a network drive during development.
  • Synchronising configuration files across multiple servers after a deployment.
  • Building a lightweight one‑way sync for a local NAS or cloud‑mounted directory.

Sponsored

Sponsored Reserved space — layout preview until AdSense is connected

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Files & data

Related tutorials and quizzes for this topic.