Path.rename

Both call the OS rename. The difference is an existing target: replace() always overwrites it (os.replace); rename() raises FileExistsError on Windows but silently overwrites on Linux and macOS (os.rename). A relative target is relative to the current directory, not to the file.

pathlib methodPython 3.4+ (return value 3.8+)Live demo
Common call
p.replace(p.with_suffix('.bak'))
Returns
the new Path
Replaces
os.rename / os.replace
Watch out
Path('dir/a.txt').rename('b.txt') moves the file OUT of dir
Path.rename(target) / Path.replace(target)
→ Path

Demo

Live evaluation
draft.txt is created with the text 'v1', then renamed.
Try:
Inputs
targetstrnew name
Code
from pathlib import Path
Path('draft.txt').write_text('v1', encoding='utf-8')
new = Path('draft.txt').rename('final.txt')
(new.as_posix(), Path('draft.txt').exists(), new.read_text(encoding='utf-8'))
Result
('final.txt', False, 'v1')

rename() returns a Path for the target; the old name no longer exists. Renaming a file to its own name is allowed and changes nothing. Moving into a folder that does not exist raises FileNotFoundError (its message is OS-specific, so it is not shown here).

Parameters

NameTypeRequiredDescription
targetstr | os.PathLikeyesNew location. Relative targets are resolved against the current working directory.

Return value

Path — A new Path for target (3.8+). The original Path object still names the old location.

Common patterns

Rename within the same folder
Build the target from the original so it stays next to it.
from pathlib import Path
p = Path('photos/IMG_0042.jpg')
p.rename(p.with_name('cat.jpg'))
Atomic file update
Write a temp file, then replace() the real one — readers see old or new, never half.
from pathlib import Path
target = Path('state.json')
tmp = target.with_name(target.name + '.tmp')
tmp.write_text(data, encoding='utf-8')
tmp.replace(target)
Move a file into another folder
Join the folder with the file name.
from pathlib import Path
src = Path('inbox/invoice.pdf')
src.replace(Path('archive') / src.name)

Examples

1. Rename and get the new path
from pathlib import Path Path('old.txt').touch() Path('old.txt').rename('new.txt').name
Returns
'new.txt'
2. The old name is gone
from pathlib import Path Path('old.txt').touch() Path('old.txt').rename('new.txt') (Path('old.txt').exists(), Path('new.txt').exists())
Returns
(False, True)
3. replace() overwrites
from pathlib import Path Path('a.txt').write_text('A', encoding='utf-8') Path('b.txt').write_text('B', encoding='utf-8') Path('a.txt').replace('b.txt') Path('b.txt').read_text(encoding='utf-8')
Returns
'A'
4. Move into a folder
from pathlib import Path Path('archive').mkdir() Path('report.pdf').touch() Path('report.pdf').replace(Path('archive') / 'report.pdf').as_posix()
Returns
'archive/report.pdf'
5. Folders can be renamed too
from pathlib import Path Path('build').mkdir() Path('build').rename('dist').is_dir()
Returns
True
6. Missing source
from pathlib import Path try: Path('ghost.txt').rename('x.txt') except OSError as e: result = type(e).__name__ result
Returns
'FileNotFoundError'

Pitfalls

1. Relative targets are relative to the cwd
The target is not interpreted relative to the file's folder, so a bare name moves the file up to the current directory.
rename('b.txt')
from pathlib import Path
Path('docs').mkdir()
Path('docs/a.txt').touch()
Path('docs/a.txt').rename('b.txt').as_posix()
'b.txt'
with_name()
from pathlib import Path
Path('docs').mkdir()
Path('docs/a.txt').touch()
p = Path('docs/a.txt')
p.rename(p.with_name('b.txt')).as_posix()
'docs/b.txt'
2. Using rename() to overwrite portably
On Windows rename() refuses an existing target, on POSIX it overwrites — replace() behaves the same everywhere.
rename (OS-dependent)
import os
from pathlib import Path
Path('a').touch()
Path('b').touch()
try:
    Path('a').rename('b')
    result = 'overwritten'
except FileExistsError:
    result = 'FileExistsError'
result == ('FileExistsError' if os.name == 'nt' else 'overwritten')
True
replace (same everywhere)
from pathlib import Path
Path('a').write_text('new', encoding='utf-8')
Path('b').write_text('old', encoding='utf-8')
Path('a').replace('b')
Path('b').read_text(encoding='utf-8')
'new'
3. Still using the old Path object
Path objects are just names. After rename, the original object points at a location that is now empty — use the return value.
old object
from pathlib import Path
p = Path('v1.txt')
p.touch()
p.rename('v2.txt')
p.exists()
False
returned object
from pathlib import Path
p = Path('v1.txt')
p.touch()
p = p.rename('v2.txt')
p.exists()
True

When to use

Use it
  • Renaming or moving within one file system
  • Atomic updates: write a temp file, then replace()
Reach for something else
  • Moving across drives / file systems → shutil.move (rename fails with OSError there)
  • Copying → shutil.copy2 (Path.copy arrives in 3.14)

Notes

CPython impl
Lib/pathlib/_local.py: os.rename(self, target) / os.replace(self, target), then return self.with_segments(target)
Overwrite
replace: always. rename: POSIX yes (for files), Windows no — FileExistsError
Across devices
Both fail when source and target are on different file systems; shutil.move copies and deletes instead
Changed in 3.8
Both return the new Path instead of None

FAQ

p.rename(p.with_name('new-name.txt')) — building the target from p keeps the file in the same folder. The method returns the new Path.