Python shutil.move(): Move Files and Folders

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 is shutil.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

Official references

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.

Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
PRAR
PRAR
3 years ago

What are the exceptions that these two methods can throw?

Pratik Kinage
Admin
3 years ago
Reply to  PRAR

According to source code, it throws Error, OSError, and PermissionError. You can check here.