os.remove

remove and unlink are the same operation: delete one file (never a folder). For renaming, prefer os.replace: it overwrites an existing destination on Linux, macOS and Windows alike, and is atomic on POSIX when both paths are on the same file system. os.rename overwrites on POSIX but raises FileExistsError on Windows.

os functionPython 3.0+ (replace 3.3+)Live demo
Common call
os.replace('data.json.tmp', 'data.json')
Returns
None
Replaces
Copy-then-delete, and remove-then-rename (which is not atomic)
Watch out
os.rename over an existing file fails on Windows; remove() never deletes folders
os.remove(path) / os.unlink(path) / os.rename(src, dst) / os.replace(src, dst) / os.renames(old, new)
→ None

Demo

Live evaluation
Create some files, delete one, list what is left.
Try:
Inputs
fileslist[str]files to create, comma-separated
targetstrfile to delete
Code
import os
for f in ['a.log', 'b.log', 'keep.txt']:
    os.makedirs(os.path.dirname(f) or '.', exist_ok=True)
    open(f, 'w').close()
try:
    os.remove('a.log')
    result = sorted(os.listdir('.'))
except OSError as e:
    result = type(e).__name__
result
Result
['b.log', 'keep.txt']

A missing file raises FileNotFoundError on every OS. replace overwrote data.json — the listing shows one file whose content is now 'new.json'. Moving into archive/ works because the folder exists. renames made final/2026, moved the file, and removed tmp/a and tmp because they became empty. Not shown, because the result depends on the OS: os.remove on a folder raises IsADirectoryError on Linux and PermissionError on Windows, and os.rename onto an existing file replaces it on POSIX but raises FileExistsError on Windows.

Parameters

NameTypeRequiredDescription
path / srcstr | PathLikeyesThe file to delete, or the file or folder to rename.
dststr | PathLikeyesThe new name. Its folder must exist (except with renames, which creates it). Moving across file systems fails — use shutil.move.

Return value

None — They change the file system and return None, or raise an OSError subclass.

Common patterns

Atomic save
Readers see the old file or the new one, never a half-written one.
import os
tmp = path + '.tmp'
with open(tmp, 'w', encoding='utf-8') as f:
    f.write(text)
    f.flush()
    os.fsync(f.fileno())
os.replace(tmp, path)
Delete if present
The os equivalent of Path.unlink(missing_ok=True).
import contextlib, os
with contextlib.suppress(FileNotFoundError):
    os.remove('cache.db')
Rename by pattern
Combine listdir, splitext and replace.
import os
for name in os.listdir('.'):
    root, ext = os.path.splitext(name)
    if ext == '.jpeg':
        os.replace(name, root + '.jpg')
Move across drives or file systems
rename/replace cannot; shutil.move falls back to copy + delete.
import shutil
shutil.move('/tmp/upload.bin', '/data/upload.bin')

Examples

1. Delete a file
import os open('a.tmp', 'w').close() os.remove('a.tmp') os.listdir('.')
Returns
[]
2. A missing file
import os try: os.remove('ghost.txt') except FileNotFoundError as e: info = (type(e).__name__, e.errno) info
Returns
('FileNotFoundError', 2)
3. replace overwrites everywhere
import os for n in ['new.txt', 'old.txt']: with open(n, 'w') as f: f.write(n) os.replace('new.txt', 'old.txt') with open('old.txt') as f: text = f.read() (sorted(os.listdir('.')), text)
Returns
(['old.txt'], 'new.txt')
4. Move into another folder
import os os.mkdir('archive') open('log.txt', 'w').close() os.rename('log.txt', 'archive/log.txt') (os.listdir('.'), os.listdir('archive'))
Returns
(['archive'], ['log.txt'])
5. renames builds and prunes folders
import os os.makedirs('tmp/a') open('tmp/a/report.txt', 'w').close() os.renames('tmp/a/report.txt', 'final/2026/report.txt') sorted(os.path.join(r, n).replace(os.sep, '/') for r, ds, fs in os.walk('.') for n in ds + fs)
Returns
['./final', './final/2026', './final/2026/report.txt']
6. Errors name both paths
import os try: os.rename('ghost.txt', 'b.txt') except FileNotFoundError as e: names = (e.filename, e.filename2) names
Returns
('ghost.txt', 'b.txt')
7. Ignore a missing file
import contextlib, os with contextlib.suppress(FileNotFoundError): os.remove('maybe.tmp') 'done'
Returns
'done'

Pitfalls

1. os.rename onto an existing file
POSIX replaces the target silently; Windows raises FileExistsError. Code that works on your Mac breaks on a Windows server.
rename: OS-dependent
import os
for n in ['new.txt', 'old.txt']:
    with open(n, 'w') as f:
        f.write(n)
try:
    os.rename('new.txt', 'old.txt')
    outcome = 'replaced'
except FileExistsError:
    outcome = 'FileExistsError'
outcome == ('FileExistsError' if os.name == 'nt' else 'replaced')
True
replace: same everywhere
import os
for n in ['new.txt', 'old.txt']:
    with open(n, 'w') as f:
        f.write(n)
os.replace('new.txt', 'old.txt')
sorted(os.listdir('.'))
['old.txt']
2. Deleting a folder with os.remove
remove/unlink only delete files. Use rmdir for an empty folder, shutil.rmtree for a full one.
os.remove(folder)
import os
os.mkdir('d')
try:
    os.remove('d')
    failed = False
except OSError:
    failed = True
failed
True
os.rmdir(folder)
import os
os.mkdir('d')
os.rmdir('d')
os.listdir('.')
[]
3. Delete-then-rename to update a file
Between the two calls the file does not exist at all, and a crash leaves it missing. replace does it in one step.
remove + rename
import os
for n in ['cfg.new', 'cfg']:
    open(n, 'w').close()
os.remove('cfg')
os.rename('cfg.new', 'cfg')
os.listdir('.')
['cfg']
replace
import os
for n in ['cfg.new', 'cfg']:
    open(n, 'w').close()
os.replace('cfg.new', 'cfg')
os.listdir('.')
['cfg']

When to use

Use it
  • Deleting single files (remove)
  • Renaming or moving within one file system (replace — or rename when the target never exists)
  • Publishing a finished file atomically (write a temp file, then replace)
Reach for something else
  • Folders → os.rmdir (empty) or shutil.rmtree (full)
  • Moving between disks → shutil.move
  • Copying → shutil.copy2 / copyfile

Notes

CPython impl
remove/unlink, rename and replace are C functions in Modules/posixmodule.c (unlink(2) and rename(2) on POSIX); renames is pure Python in Lib/os.py (makedirs + rename + removedirs)
unlink
remove and unlink are two separate built-in function objects with identical behaviour; unlink is the traditional Unix name
Windows
A file that is still open (even in your own process) cannot be removed: PermissionError, [WinError 32]
Atomicity
The docs: if successful, replace on POSIX is an atomic operation (a POSIX requirement); the same applies to rename

FAQ

os.remove('file.txt') (or Path('file.txt').unlink()). It raises FileNotFoundError if the file is missing — wrap it in contextlib.suppress(FileNotFoundError) to ignore that.