The os.makedirs() function with the exist_ok=True argument is the most recommended way to create a directory if it does not exist in Python. It avoids race conditions, so it is safe in multi-threaded environments.
The os.makedirs() creates intermediate directories if they don’t exist. If the directory exists, then it will throw a FileExistsError exception.
Here is the hands-on example. Before creating a directory, our “parent” directory looks like this:
The above screenshot shows that the directory is empty.
Let me write a program to create a directory inside the above empty directory:
import os
dir_path = "parent/child/grandchild"
try:
os.makedirs(dir_path, exist_ok=True)
except OSError as e:
print(f"Error: {e}")
The screenshot above of the file system shows that it created a child directory within the parent directory and a nested directory, grandchild, inside the child directory.
The makedirs() function is recursive and creates nested directories. Setting exist_ok=True prevents FileExistsError; if the path is a file, makedirs() raises FileExistsError, and lacking permissions raises PermissionError.
import os
dir_path = "parent/child/grandchild"
try:
os.makedirs(dir_path, exist_ok=False)
except OSError as e:
print(f"Error: {e}")
# Output: Error: [Errno 17] File exists: 'parent/child/grandchild'
There is still a chance that it will throw an error like FileExistsError or PermissionError:
- If the path is an existing file (not a directory), it throws FileExistsError.
- If the directory lacks proper permissions, it raises a PermissionError.
The mode=0o777 sets permissions to rwxrwxrwx (read/write/execute); a common alternative is 0o755, which gives rwx to the owner and rx to group/others.
os.makedirs(dir_path, exist_ok=False, mode=0o777)
Bulk directory creation
Use a for loop with exist_ok=True for bulk directory creation.
import os
dir_paths = ["dir1", "dir2/subdir", "dir3"]
try:
for path in dir_paths:
os.makedirs(path, exist_ok=True)
except OSError as e:
print(f"Error: {e}")
Using pathlib (Python 3.4+)
The built-in pathlib module provides a Path.mkdir() method to construct a directory.
from pathlib import Path
dir_path = Path("parent/child/grandchild")
try:
dir_path.mkdir(parents=True, exist_ok=True)
except FileExistsError:
print(f"Error: {dir_path} is a file, not a directory.")
except PermissionError as e:
print(f"Permission denied: {e}")
Passing the parents=True argument instructs the interpreter to create parent directories if they do not exist.
The exist_ok=True argument tells no error if the directory exists.
By default, it avoids race conditions and handles path separators automatically (e.g., \ vs. /).
For example, you can use the os.path.isfile() method to check if it is a file. That will handle the FileExistsError.
Granting the proper permissions resolves the PermissionError. You need to run the command as an administrator or select a new path.
Using os.path.exists() and os.makedirs() (Not recommended)
The os.path.exists() method checks the directory’s existence, and if it does not exist, the os.makedirs() creates a new directory.
Avoid using os.path.exists() with os.makedirs(); it introduces a race condition.
You might wonder what a race condition is. The os.path.exists() checks whether a directory exists, but another process may create or remove it during the check, causing a race condition.
Within microseconds, another process can create a directory, which causes issues. So, it is not safe in multi-threaded environments.
You might ask: why use this approach? If you have to execute specific logic only if the directory did not exist before creation, you might combine os.path.exists() with the os.makedirs() method.
import os
dir_path = "parent/child/grandchild"
if not os.path.exists(dir_path):
os.makedirs(dir_path)
print("Directory created from scratch!")
else:
print("Directory already existed.")
# Output: Directory created from scratch!
That’s it!



SoftBigs
I found this article helpful. Thank you for writing it!
John Davis
Great blog post! I’m glad to see a detailed explanation of how to create a directory if it doesn’t exist in Python. This is a useful technique that I will definitely use in my own projects. Thanks for sharing!