Python mkdir if Not Exist

Introduction
Creating a directory might sound trivial, but things can go sideways when the folder already exists. Many beginners end up with a FileExistsError
, while missing race conditions can trip up even seasoned developers. So, how can you ensure your Python script creates a directory only if it doesn’t exist, without raising errors or causing conflicts?
The good news is Python’s standard library has you covered. By combining os.makedirs
or pathlib.Path.mkdir
with simple checks and exception handling, you can write robust code that works safely in single-threaded and concurrent scenarios. Let’s dive in!
Why Check Existence
Before creating a directory, it’s tempting to just call mkdir()
and move on. But consider:
- Redundant errors when the folder exists.
- Race conditions if two processes run concurrently.
- Unexpected overwrites if permissions differ.
By explicitly handling the “exists” case, your script stays predictable. You can log meaningful messages, set permissions correctly, or even clean up old files.
Using os.makedirs
Python’s os
module provides makedirs()
, which creates all intermediate-level directories needed to contain the leaf directory. To ignore FileExistsError
, pass exist_ok=True
in Python 3:
import os
path = 'data/output/logs'
# Creates nested dirs, no error if already there
os.makedirs(path, exist_ok=True)
If you need custom error handling (e.g., permissions issues), wrap it in a try/except:
try:
os.makedirs(path)
print(f"Directory '{path}' created.")
except FileExistsError:
print(f"Directory '{path}' already exists.")
except OSError as e:
print(f"Failed to create directory: {e}")
Tip: Use
exist_ok=True
to simplify cases where you don’t need special logic on existing folders.
Using pathlib Path
The pathlib
module offers an object-oriented approach:
from pathlib import Path
path = Path('data/output/logs')
# Creates dir, no error if exists
path.mkdir(parents=True, exist_ok=True)
Pathlib makes chaining operations easier:
file_path = path / 'app.log'
file_path.write_text('Log started')
Handling Race Conditions
In multi-threaded or multi-process code, a folder check followed by creation can still cause conflicts:
from pathlib import Path
path = Path('shared/cache')
# Danger: Might fail if created between check and mkdir
if not path.exists():
path.mkdir()
Better to rely on built-in flags:
try:
path.mkdir(parents=True)
except FileExistsError:
pass # Safe: someone else created it
This pattern avoids a separate existence check and handles the edge case gracefully.
Setting Permissions
Sometimes you need custom permissions (e.g., 0o755
). Both os.makedirs
and pathlib.Path.mkdir
accept a mode
argument:
import os
os.makedirs('scripts', mode=0o755, exist_ok=True)
# Or with pathlib
from pathlib import Path
Path('scripts').mkdir(mode=0o755, exist_ok=True)
Make sure your umask doesn’t mask out intended bits. If necessary, adjust it at runtime:
old_umask = os.umask(0)
os.makedirs('reports', mode=0o777, exist_ok=True)
os.umask(old_umask)
Working with Files After Creation
Once your directory exists, you often create or move files into it. For moving, check out how to move files in Python. To inspect content, the guide on listing directory contents in Python is handy.
Example:
import shutil
target = Path('cache/data.csv')
if not target.exists():
# generate data
with open(target, 'w') as f:
f.write('id,value\n1,100')
# Move to archive
archive_dir = Path('archive')
archive_dir.mkdir(exist_ok=True)
shutil.move(str(target), str(archive_dir / target.name))
Conclusion
Safely creating directories in Python is straightforward when you leverage exist_ok=True
and proper exception handling. Use os.makedirs
for procedural code or pathlib.Path.mkdir
for a more readable approach. Always handle race conditions and set permissions explicitly to avoid surprises. With these patterns in your toolkit, your file and folder operations will be robust and maintainable.
Subscribe to my newsletter
Read articles from Mateen Kiani directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
