Python shutil.move() moves a file or directory from one path to another. It is part of the standard-library shutil module and is useful when you need higher-level file operations than a simple rename.
The function accepts source and destination paths, then returns the final destination path as a string. If the move crosses filesystems, shutil.move() may copy the data and remove the original, using copy2 by default for file metadata.
shutil.move syntax
shutil.move(src, dst, copy_function=shutil.copy2)
src: source file or directory path.dst: destination path or destination directory.copy_function: function used when copying is needed. The default isshutil.copy2.
If dst is an existing directory, the source is moved inside that directory. If dst is a full file path, the source is moved or renamed to that exact path.
Move one file
from pathlib import Path
from shutil import move
source = Path("incoming/report.txt")
destination = Path("archive") / source.name
result = move(str(source), str(destination))
print(result)
This moves incoming/report.txt to archive/report.txt. The call removes the original source file after the destination is created.
Move a directory
from pathlib import Path
from shutil import move
source_dir = Path("source")
done_dir = Path("done")
result = move(str(source_dir), str(done_dir))
print(result)
If done does not exist, the source directory is moved and renamed to done. If the destination already exists as a directory, the source directory is moved inside it.
Move matching files with glob
shutil.move() moves one source path at a time. To move several matching files, loop over Path.glob():
from pathlib import Path
from shutil import move
incoming = Path("incoming")
archive = Path("archive")
archive.mkdir(exist_ok=True)
for path in incoming.glob("*.csv"):
move(str(path), str(archive / path.name))
This example moves every CSV file from incoming to archive and leaves non-CSV files alone.
shutil.move vs os.rename
os.rename() is a lower-level rename operation. It is often fast when the source and destination are on the same filesystem, but it is less convenient when you want high-level copy-and-remove behavior across filesystems.
shutil.move() is usually the better default for scripts because it handles files, directories, and cross-filesystem moves with one API. Use os.rename() when you specifically want rename semantics and already know the operation is valid for your platform and filesystem.
Overwrite and destination rules
- If the destination is an existing directory, the source is moved into that directory.
- If the destination file path exists, behavior depends on the operating system and file type. Avoid accidental overwrites by checking
Path.exists()first. - If a directory destination conflicts with an existing path, Python raises an error instead of silently merging everything.
- If another process has the file open, Windows can raise a permission or sharing error.
Safer move helper
from pathlib import Path
from shutil import move
def safe_move(src, dst):
src_path = Path(src)
dst_path = Path(dst)
if not src_path.exists():
raise FileNotFoundError(src_path)
if dst_path.exists():
raise FileExistsError(dst_path)
return move(str(src_path), str(dst_path))
This helper is intentionally strict: it refuses to move missing sources and refuses to overwrite existing destinations.
Common errors and fixes
FileNotFoundError means the source path does not exist from the current working directory. Print Path.cwd() or use absolute paths while debugging. PermissionError usually means the process does not have access to the file or another program is locking it.
On Windows, moving an open file can fail with a sharing error. Close the file handle before moving it, and avoid moving a file that is still open in another application. On Linux and macOS, permissions and destination ownership are more common causes.
For cross-filesystem moves, remember that shutil.move() may copy and then delete the source. That can be slower than a same-filesystem rename, and it can fail if the destination filesystem runs out of space. For important data, verify the destination before deleting backups.
Pathlib and string paths
Modern Python functions increasingly accept path-like objects, but converting Path objects with str() keeps examples compatible and explicit. The important part is to build paths with Path or the / operator instead of hand-writing separators such as \ or / inside long strings.
destination = archive / source.name
move(str(source), str(destination))
This avoids common path bugs when the same script runs on different operating systems.
Related Python guides
- Python shutil module
- Python shutil.rmtree()
- Python rename file
- Copy file using Python
- Delete a file in Python
- Get current directory in Python
Official references
- Python shutil.move documentation
- Python shutil.copy2 documentation
- Python os.rename documentation
- Python pathlib documentation
Conclusion
Use shutil.move() when you need a clear standard-library way to move files or folders. Pass full destination paths when you want precise results, check for existing destinations before overwriting, and use Path.glob() when you need to move a batch of matching files.
What are the exceptions that these two methods can throw?
According to source code, it throws Error, OSError, and PermissionError. You can check here.