The Downloads Folder Problem
Open your Downloads folder. Screenshots from last week, PDFs from three months ago, installers, zip files, random images, a .deb package you don't remember downloading. It's chaos.
Manually sorting files is boring and nobody does it. But a Python script will do it in 0.2 seconds, every time.
By the end of this guide, you'll have a script that turns this:
Downloads/
├── IMG_4529.png
├── tax-return-2025.pdf
├── ubuntu-26.04.iso
├── movie-night.mp4
├── resume-final-v2.docx
├── song.mp3
└── random-meme.gif
Into this:
Downloads/
├── Images/
│ ├── IMG_4529.png
│ └── random-meme.gif
├── Documents/
│ ├── tax-return-2025.pdf
│ └── resume-final-v2.docx
├── Videos/
│ └── movie-night.mp4
├── Music/
│ └── song.mp3
└── Archives/
└── ubuntu-26.04.iso
The Full Script (Then We'll Explain Every Line)
#!/usr/bin/env python3
"""Organize files in a folder by their extension."""
import os
import shutil
from pathlib import Path
# ── Config ──
FOLDER_TO_ORGANIZE = Path.home() / "Downloads" # Change this if needed
# Map extensions to folder names
CATEGORIES = {
# Images
".jpg": "Images", ".jpeg": "Images", ".png": "Images",
".gif": "Images", ".webp": "Images", ".svg": "Images",
".bmp": "Images", ".ico": "Images",
# Documents
".pdf": "Documents", ".docx": "Documents", ".doc": "Documents",
".txt": "Documents", ".md": "Documents", ".csv": "Documents",
".xlsx": "Documents", ".pptx": "Documents", ".odt": "Documents",
# Videos
".mp4": "Videos", ".mov": "Videos", ".avi": "Videos",
".mkv": "Videos", ".webm": "Videos",
# Music
".mp3": "Music", ".wav": "Music", ".flac": "Music",
".aac": "Music", ".ogg": "Music",
# Archives & installers
".zip": "Archives", ".tar.gz": "Archives", ".gz": "Archives",
".rar": "Archives", ".7z": "Archives", ".deb": "Archives",
".iso": "Archives", ".AppImage": "Archives",
# Code
".py": "Code", ".js": "Code", ".html": "Code",
".css": "Code", ".json": "Code", ".sh": "Code",
}
def organize(folder: Path):
"""Move files in `folder` into categorized subfolders."""
moved = 0
skipped = 0
for item in folder.iterdir():
# Skip directories, hidden files, and this script itself
if item.is_dir():
continue
if item.name.startswith("."):
continue
# Get the file extension (lowercase for matching)
ext = item.suffix.lower()
# Handle double extensions like .tar.gz
if item.name.endswith(".tar.gz"):
ext = ".tar.gz"
# Find the right category
category = CATEGORIES.get(ext)
if category is None:
print(f" ⏭ Skipped (unknown type): {item.name}")
skipped += 1
continue
# Create the category folder if it doesn't exist
dest_dir = folder / category
dest_dir.mkdir(exist_ok=True)
# Handle duplicate file names
dest = dest_dir / item.name
if dest.exists():
# Append a number instead of overwriting
stem = item.stem
counter = 1
while dest.exists():
dest = dest_dir / f"{stem}_{counter}{ext}"
counter += 1
# Move the file
shutil.move(str(item), str(dest))
print(f" ✓ {item.name} → {category}/")
moved += 1
print(f"\nDone! Moved {moved} files, skipped {skipped}.")
if __name__ == "__main__":
print(f"Organizing: {FOLDER_TO_ORGANIZE}")
organize(FOLDER_TO_ORGANIZE)
How It Works
1. Finding Your Downloads Folder
FOLDER_TO_ORGANIZE = Path.home() / "Downloads"
Path.home() returns your home directory — /home/alice on Linux, C:\Users\alice on Windows, /Users/alice on Mac. Then we append Downloads. This works cross-platform without any if statements.
2. The Extension-to-Category Map
CATEGORIES = {
".jpg": "Images", ".png": "Images", ".gif": "Images",
".pdf": "Documents", ".docx": "Documents",
...
}
A dictionary that maps every file extension to a folder name. To add your own types, just add entries. Want Photoshop files to go to "Design"? Add ".psd": "Design".
3. Iterating Through Files
for item in folder.iterdir():
if item.is_dir():
continue # Skip folders
if item.name.startswith("."):
continue # Skip hidden files
iterdir() goes through every file in the folder one by one. We skip directories (we only organize files) and hidden files (files starting with . like .bashrc).
4. Getting the Extension
ext = item.suffix.lower()
if item.name.endswith(".tar.gz"):
ext = ".tar.gz"
suffix returns the extension (.JPG → .jpg after lower()). The .tar.gz case is special — suffix only returns .gz, so we check for the full .tar.gz ending.
5. Handling Duplicates
if dest.exists():
counter = 1
while dest.exists():
dest = dest_dir / f"{stem}_{counter}{ext}"
counter += 1
If you download report.pdf twice, the second one becomes report_1.pdf instead of overwriting the first. The while loop keeps incrementing the counter until it finds an unused name.
Customizing the Script
Change the folder
# Organize a specific folder instead of Downloads
FOLDER_TO_ORGANIZE = Path("/home/alice/Desktop/Stuff")
Add your own file types
# Add these to the CATEGORIES dict:
".epub": "Books",
".mobi": "Books",
".psd": "Design",
".xd": "Design",
Run on a schedule (Linux cron)
# Run every hour
0 * * * * python3 /home/alice/scripts/organize_downloads.py
If you're new to cron, our Linux Terminal Basics guide includes cron fundamentals. For a complete backup solution using the same idea, see our Python Automated Backups guide.
What to Do Next
Once this script works for you, try these variations:
- Add a dry-run mode — print what would move without actually moving anything
- Organize by date — move files into
2026-08/,2026-07/, etc. instead of by type - Log to a file — keep a record of every move for when you can't find something
- Watch mode — use
watchdoglibrary to automatically organize new files as they're downloaded
For another practical Python automation project, check out our File Renaming guide — a 10-line script that renames hundreds of files in seconds.
The best part about this script? You write it once and it works forever. I've been running mine for months. My Downloads folder has never been cleaner — and I haven't manually sorted a single file.