If you need a folder tree such as data/reports/2026 before writing logs or exports, Python’s standard library gives you two solid tools: pathlib.Path.mkdir (usually preferred) and os.makedirs. This page puts pathlib first, matches the official Path.mkdir signature (parents, exist_ok), then covers os.makedirs, comparisons, creating parents before saving a file, errors, and why distutils is obsolete.
Examples use relative paths like data/reports/2026 and, where a full path helps, Path.home() / "reports" so the ideas work on Windows and Linux. Each fenced example is a complete script (imports included) that creates directories under tempfile.TemporaryDirectory() so it does not touch your project tree. Those operations are file system I/O: the opening fences use {run=false} so the in-page Run control is not offered on Cloudflare Pages (Judge0 may block or vary temp filesystem behavior). Copy the snippet into a local python3 shell or script for the same output.
Tested on: Python 3.13.3; kernel 6.14.0-37-generic.
Best way to create directories recursively in Python
Use pathlib.Path with parents=True (create missing parents) and exist_ok=True (do not fail if the leaf directory already exists):
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / "logs" / "2026" / "06"
path.mkdir(parents=True, exist_ok=True)
print(path.is_dir())You should see True: the whole chain logs/2026/06 exists under the temp root. That pattern maps directly to project code such as Path("data/reports/2026") when tmp is your working tree.
Create nested directories using pathlib Path.mkdir()
Path.mkdir follows mkdir(mode=0o777, parents=False, exist_ok=False) in the docs. For nested trees you almost always want parents=True. Use mode= only when you care about permission bits on POSIX; on Windows it may be partially ignored.
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as tmp:
nested = Path(tmp) / "data" / "reports" / "2026"
nested.mkdir(parents=True, exist_ok=False)
print(nested)Running it prints an absolute path ending in .../data/reports/2026. A second run with the same path and exist_ok=False would raise FileExistsError unless you set exist_ok=True.
Create directory if it does not exist using pathlib
Set exist_ok=True when rerunning scripts or tests should not crash if the directory is already there. The docs note that exist_ok=True does not help if a file already sits where you want a directory—you still get FileExistsError. See check if a path exists before creating when you expect collisions.
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / "cache" / "session"
path.mkdir(parents=True, exist_ok=True)
path.mkdir(parents=True, exist_ok=True)
print("ok", path.is_dir())You should see ok True twice in spirit—the second mkdir is a no-op for an existing directory.
Create nested directories using os.makedirs()
os.makedirs creates the leaf directory and any intermediate ones. With exist_ok=False (the default), an existing target directory raises FileExistsError.
import os
import tempfile
with tempfile.TemporaryDirectory() as tmp:
target = os.path.join(tmp, "logs", "2026", "06")
os.makedirs(target, exist_ok=True)
print(os.path.isdir(target))You should see True. Prefer os.path.join (or pathlib) over hardcoding \ or / so the same code runs cross-platform.
Create directory if it does not exist using os.makedirs
Pass exist_ok=True for idempotent setup, the same idea as Path.mkdir(..., exist_ok=True).
import os
import tempfile
with tempfile.TemporaryDirectory() as tmp:
target = os.path.join(tmp, "out", "render")
os.makedirs(target, exist_ok=True)
os.makedirs(target, exist_ok=True)
print("ready")This prints ready without error. If a file named render already exists, both APIs fail with FileExistsError when you try to create a directory at that path.
pathlib mkdir vs os.makedirs
Path.mkdir(parents=True, exist_ok=True) |
os.makedirs(..., exist_ok=True) |
|
|---|---|---|
| Style | Object-oriented Path objects |
String paths with os |
| Typical use | New application code, composition with read_text / write_text |
Legacy scripts, glue next to other os.* calls |
| Parents | parents=True |
Always recursive for the full path |
| Existence | exist_ok=True |
exist_ok=True (Python 3.2+) |
Pick one style per module for consistency; mixing is fine at boundaries if you convert with Path(p) or os.fspath(p).
Create parent folders before writing a file
Real code often needs the parent of a file path, not the file itself:
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as tmp:
file_path = Path(tmp) / "reports" / "2026" / "june" / "output.txt"
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text("Report generated")
print(file_path.read_text())You should see Report generated. On user-owned trees you can build under the home directory without hardcoding separators, for example Path.home() / "reports" / "2026" (same mkdir on .parent before writing). The same mkdir(parents=True, exist_ok=True) on target.parent is required before a rename or move in Python when the destination folder does not exist yet.
Handle errors while creating directories
Catch PermissionError when the process lacks rights, and OSError for other platform issues (disk full, read-only filesystem, invalid name).
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / "logs" / "2026" / "06"
try:
path.mkdir(parents=True, exist_ok=True)
print("created", path.is_dir())
except PermissionError:
print("Permission denied")
except OSError as error:
print(f"Could not create directory: {error}")In normal temp setups this prints created True. For more on failures when opening paths, see FileNotFoundError in Python.
Why distutils.dir_util.mkpath should be avoided
Older tutorials used distutils.dir_util.mkpath(). distutils was removed from the standard library in Python 3.12 (deprecated earlier in 3.10). Do not teach it as a current option; use pathlib.Path.mkdir or os.makedirs instead and migrate any legacy mkpath call sites.
Common mistakes when creating directories
- Omitting
parents=Trueand then wondering why a nested path raisesFileNotFoundErrorbecause an intermediate folder is missing. - Omitting
exist_ok=Truein idempotent jobs so reruns raiseFileExistsErroreven though the tree is already correct. - Importing or copying
distutilsexamples into a Python 3.12+ environment where the module is gone. - Calling
mkdiron a path where a file already exists with the same name—bothpathlibandosrefuse to replace a file with a directory via these calls. - Hardcoding
C:\...or mixing/and\by hand; preferPath(...)oros.path.join. - Opening
Path("reports/june.txt")for write without creatingPath("reports")first—create.parent(or useopenhelpers that document who creates parents). - Swallowing all errors: at minimum distinguish
PermissionErrorfrom otherOSErrortypes so operators can react.
Python create directory quick reference table
| Need | Approach |
|---|---|
| Recursive create (modern) | Path("a/b/c").mkdir(parents=True, exist_ok=True) |
Recursive create (os) |
os.makedirs(os.path.join("a", "b", "c"), exist_ok=True) |
| Parents only for a file | file_path.parent.mkdir(parents=True, exist_ok=True) |
| Default “fail if exists” | omit exist_ok or pass False |
| Sum of permission details on POSIX | set mode= on mkdir where documented |
Summary
For recursive directory creation in current Python, start with pathlib.Path.mkdir(parents=True, exist_ok=True); use os.makedirs(..., exist_ok=True) when string paths and the os module fit your codebase. Create parent directories before writing files with file_path.parent.mkdir(...). Handle PermissionError and OSError, and do not rely on distutils—it is gone from the stdlib in 3.12+. For writing after the tree exists, follow up with write to file patterns in your app.
References
pathlib.Path.mkdir(Python 3)os.makedirs(Python 3)- PEP 632 — Removal of distutils
Frequently Asked Questions
What is the best way to create nested directories in Python?
Prefer pathlib.Path.mkdir(parents=True, exist_ok=True) for new code; use os.makedirs(path, exist_ok=True) when you already work with str paths in os-heavy code.
What does parents=True do in Path.mkdir?
It creates any missing parent directories along the path; without it, a missing parent raises FileNotFoundError.
What does exist_ok=True do for mkdir and makedirs?
If the target directory already exists, no error is raised; if a file exists at the same path, you still get FileExistsError.
Why should I avoid distutils.dir_util.mkpath?
distutils was removed from the standard library in Python 3.12; use pathlib or os.makedirs instead.

