How to Merge Multiple Folders into One Folder Using Python
When managing files on your computer, you may need to consolidate the contents of multiple folders into a single destination folder. This is common when organizing downloaded files, combining project assets, or restructuring directory layouts. Doing this manually is tedious and error-prone, especially when dealing with dozens of folders containing hundreds of files.
In this guide, you'll learn how to automate this process using Python's built-in os and shutil modules, handle edge cases like duplicate filenames, and build a clean, reusable solution.
Prerequisites
This guide uses only Python's built-in modules: no external packages are required:
os: for navigating directories, listing files, and creating folders.shutil: for moving files and folders between locations.
Understanding the Approach
The strategy for merging multiple folders is straightforward:
- Identify the source folders you want to merge.
- Collect the contents (files and subfolders) of each source folder.
- Create the destination folder if it doesn't already exist.
- Move all contents from each source folder into the destination.
Step-by-Step Implementation
Step 1: List Source Folders and Their Contents
First, define which folders you want to merge and gather their contents:
import os
# Working directory
current_folder = os.getcwd()
# Folders to merge
list_dir = ['Folder 1', 'Folder 2', 'Folder 3']
# Collect the contents of each folder
content_list = {}
for folder_name in list_dir:
folder_path = os.path.join(current_folder, folder_name)
content_list[folder_name] = os.listdir(folder_path)
# Display what was found
for folder, files in content_list.items():
print(f"{folder}: {files}")
Output (example):
Folder 1: ['File1.txt', 'File2.txt']
Folder 2: ['File3.txt', 'File4.txt']
Folder 3: ['File5.txt', 'File6.txt']
Step 2: Create the Destination Folder
Create the merge destination folder if it doesn't already exist. Using os.makedirs() with exist_ok=True is the cleanest approach:
merge_folder = "merge_folder"
merge_folder_path = os.path.join(current_folder, merge_folder)
# Create the folder (no error if it already exists)
os.makedirs(merge_folder_path, exist_ok=True)
print(f"Destination folder ready: {merge_folder_path}")
Use os.makedirs(path, exist_ok=True) instead of manually checking with os.path.exists() or catching OSError. It's more concise and handles nested directory creation automatically.
Step 3: Move All Contents to the Destination
Loop through each source folder and move its contents into the destination:
import shutil
for folder_name, contents in content_list.items():
for item in contents:
source_path = os.path.join(current_folder, folder_name, item)
destination_path = os.path.join(merge_folder_path, item)
shutil.move(source_path, destination_path)
print(f"Moved: {source_path} → {destination_path}")
Output (example):
Moved: /home/user/Folder 1/File1.txt → /home/user/merge_folder/File1.txt
Moved: /home/user/Folder 1/File2.txt → /home/user/merge_folder/File2.txt
Moved: /home/user/Folder 2/File3.txt → /home/user/merge_folder/File3.txt
...
Complete Code
Here's the full, clean implementation:
import os
import shutil
def merge_folders(source_folders, destination_folder, base_path=None):
"""
Merge the contents of multiple source folders into a single destination folder.
Args:
source_folders: List of folder names to merge.
destination_folder: Name of the destination folder.
base_path: Base directory path. Defaults to current working directory.
"""
if base_path is None:
base_path = os.getcwd()
destination_path = os.path.join(base_path, destination_folder)
# Create destination folder if it doesn't exist
os.makedirs(destination_path, exist_ok=True)
# Collect contents of each source folder
content_map = {}
for folder in source_folders:
folder_path = os.path.join(base_path, folder)
if os.path.isdir(folder_path):
content_map[folder] = os.listdir(folder_path)
else:
print(f"Warning: '{folder}' does not exist, skipping.")
# Move all contents to the destination
moved_count = 0
for folder_name, contents in content_map.items():
for item in contents:
source = os.path.join(base_path, folder_name, item)
destination = os.path.join(destination_path, item)
shutil.move(source, destination)
moved_count += 1
print(f"Done! Moved {moved_count} items into '{destination_folder}'.")
# Define source folders and destination
source_folders = ['Folder 1', 'Folder 2', 'Folder 3']
destination = 'merge_folder'
# Run the merge
merge_folders(source_folders, destination)
Folder Structure Before Running
project/
├── Folder 1/
│ ├── File1.txt
│ └── File2.txt
├── Folder 2/
│ ├── File3.txt
│ └── File4.txt
├── Folder 3/
│ ├── File5.txt
│ └── File6.txt
├── Folder 4/
│ ├── File7.txt
│ └── File8.txt
└── merge_script.py
Folder Structure After Running
project/
├── Folder 1/ (empty)
├── Folder 2/ (empty)
├── Folder 3/ (empty)
├── Folder 4/ (untouched)
│ ├── File7.txt
│ └── File8.txt
├── merge_folder/
│ ├── File1.txt
│ ├── File2.txt
│ ├── File3.txt
│ ├── File4.txt
│ ├── File5.txt
│ └── File6.txt
└── merge_script.py
Notice that Folder 4 is untouched because it wasn't included in the source_folders list.
Handling Duplicate Filenames
A common issue arises when multiple source folders contain files with the same name. By default, shutil.move() will overwrite the existing file in the destination without warning.
# ❌ If Folder 1 and Folder 2 both contain "report.txt",
# the second move silently overwrites the first one
shutil.move("Folder 1/report.txt", "merge_folder/report.txt")
shutil.move("Folder 2/report.txt", "merge_folder/report.txt") # Overwrites!
To avoid data loss, rename duplicates before moving:
import os
import shutil
def safe_move(source, destination_dir):
"""
Move a file to the destination directory, renaming it if a
file with the same name already exists.
"""
filename = os.path.basename(source)
destination = os.path.join(destination_dir, filename)
# If a file with the same name exists, add a counter suffix
if os.path.exists(destination):
name, ext = os.path.splitext(filename)
counter = 1
while os.path.exists(destination):
new_filename = f"{name}_{counter}{ext}"
destination = os.path.join(destination_dir, new_filename)
counter += 1
print(f"Renamed: '{filename}' → '{os.path.basename(destination)}'")
shutil.move(source, destination)
# Usage
safe_move("Folder 1/report.txt", "merge_folder")
safe_move("Folder 2/report.txt", "merge_folder") # Saved as report_1.txt
Output:
Renamed: 'report.txt' → 'report_1.txt'
Always account for duplicate filenames when merging folders. Silent overwrites can cause permanent data loss. Use the safe_move() function above or check for conflicts before moving.
Copying Instead of Moving
If you want to keep the original files in their source folders and only create copies in the destination, use shutil.copy2() instead of shutil.move():
import shutil
# Copy instead of move (preserves metadata like timestamps)
shutil.copy2(source_path, destination_path)
shutil.copy2() vs shutil.copy()shutil.copy()copies the file content and permissions.shutil.copy2()additionally preserves the file's metadata (modification time, creation time, etc.).
Use copy2() when you want an exact replica of the original file.
Cleaning Up Empty Source Folders
After moving all files, the source folders will be empty. You can optionally remove them:
import os
source_folders = ['Folder 1', 'Folder 2', 'Folder 3']
for folder in source_folders:
folder_path = os.path.join(os.getcwd(), folder)
try:
os.rmdir(folder_path) # Only removes empty directories
print(f"Removed empty folder: {folder}")
except OSError:
print(f"Skipped '{folder}' (not empty)")
os.rmdir() only removes empty directories, so it's safe to call: it won't accidentally delete folders that still contain files.
Summary
| Task | Function |
|---|---|
| List folder contents | os.listdir() |
| Create destination folder | os.makedirs(path, exist_ok=True) |
| Move files | shutil.move() |
| Copy files (keep originals) | shutil.copy2() |
| Remove empty folders | os.rmdir() |
Merging multiple folders into one using Python is a straightforward process: list the source folders, collect their contents, create the destination directory, and move everything over. Always handle duplicate filenames to prevent data loss, and consider using shutil.copy2() instead of shutil.move() if you want to preserve the original files. Wrap the logic in a reusable function to keep your code clean and maintainable.