Path.symlink_to
The path you call it on is the LINK; the argument is what it points to — the reverse of os.symlink(src, dst). Creating symlinks on Windows needs Developer Mode or admin rights, so this page shows hard links in its runnable examples.
Common call
Path('current').symlink_to('releases/v2')
Returns
None (readlink: the target Path)
Replaces
os.symlink(target, link) / os.link / os.readlink
Watch out
argument order is link.symlink_to(target)
Path.symlink_to(targettarget — What the link points to. For symlinks it is stored as given — a relative target is relative to the link's folder, not the cwd.type: str | os.PathLike · required, target_is_directorytarget_is_directory — symlink_to only: must be True on Windows when target is a folder; ignored elsewhere.type: bool · default: False=False) / .hardlink_to(target) / .readlink()
→ None | Path
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| target | str | os.PathLike | yes | What the link points to. For symlinks it is stored as given — a relative target is relative to the link's folder, not the cwd. |
| target_is_directory | bool | no (False) | symlink_to only: must be True on Windows when target is a folder; ignored elsewhere. |
Return value
None | Path — symlink_to / hardlink_to return None; readlink returns the stored target as a Path.
Common patterns
"current" release pointer
Point a stable name at a versioned folder.
from pathlib import Path link = Path('current') link.unlink(missing_ok=True) link.symlink_to('releases/v2', target_is_directory=True)
Where does this link point?
readlink gives the stored target; resolve() gives the final absolute path.
from pathlib import Path link = Path('/usr/bin/python3') if link.is_symlink(): print(link.readlink(), link.resolve())
Deduplicate with hard links
Both names share the same data on disk.
from pathlib import Path Path('copy.iso').hardlink_to('original.iso')
Examples
1. A hard link shares the content
from pathlib import Path
Path('orig.txt').write_text('shared', encoding='utf-8')
Path('link.txt').hardlink_to('orig.txt')
Path('link.txt').read_text(encoding='utf-8')
Returns
'shared'2. It is the same file
from pathlib import Path
Path('orig.txt').touch()
Path('link.txt').hardlink_to('orig.txt')
Path('link.txt').samefile('orig.txt')
Returns
True3. Link count goes up
from pathlib import Path
Path('orig.txt').touch()
Path('link.txt').hardlink_to('orig.txt')
Path('orig.txt').stat().st_nlink
Returns
24. A hard link is not a symlink
from pathlib import Path
Path('orig.txt').touch()
Path('link.txt').hardlink_to('orig.txt')
Path('link.txt').is_symlink()
Returns
False5. The link name must be free
from pathlib import Path
Path('a').touch()
Path('b').touch()
try:
Path('b').hardlink_to('a')
except OSError as e:
result = type(e).__name__
result
Returns
'FileExistsError'Pitfalls
1. Swapping link and target
os.symlink(src, dst) and Path.symlink_to use opposite orders: the Path is the new link. The same holds for hardlink_to — swapped, it looks for a target that does not exist.
target.hardlink_to(link)
from pathlib import Path Path('data.txt').touch() try: Path('data.txt').hardlink_to('backup.txt') except OSError as e: result = type(e).__name__ result
'FileNotFoundError'
link.hardlink_to(target)
from pathlib import Path Path('data.txt').touch() Path('backup.txt').hardlink_to('data.txt') Path('backup.txt').exists()
True
2. Relative symlink targets
A symlink stores its target text as-is, and the OS interprets a relative target from the link's own folder. Build the target relative to the link, not to the cwd.
relative to cwd
from pathlib import PurePosixPath link = PurePosixPath('links/app.log') target = PurePosixPath('logs/app.log') (link.parent / target).as_posix()
'links/logs/app.log'
relative to the link
from pathlib import PurePosixPath link = PurePosixPath('links/app.log') target = PurePosixPath('logs/app.log') rel = target.relative_to(link.parent, walk_up=True) (rel.as_posix(), (link.parent / rel).as_posix())
('../logs/app.log', 'links/../logs/app.log')
When to use
Use it
- Stable names pointing at versioned files or folders (symlink_to)
- Saving space for identical files on one file system (hardlink_to)
- Inspecting link targets (readlink)
Reach for something else
- Copying content → shutil.copy2
- Hard links across file systems or to folders → not possible; use a symlink
Notes
CPython impl
Lib/pathlib/_local.py: symlink_to = os.symlink(target, self, target_is_directory); hardlink_to = os.link(target, self); readlink = with_segments(os.readlink(self)); each is only defined when os has the function, else UnsupportedOperation
Windows
Creating symlinks needs Developer Mode or the SeCreateSymbolicLinkPrivilege (usually admin); hard links work on NTFS without it
Changed in 3.13
Missing OS support raises UnsupportedOperation instead of NotImplementedError
link_to
The old Path.link_to (with the reversed argument order) was removed in 3.12; use hardlink_to
FAQ
Path('link_name').symlink_to('target'). The Path is the link, the argument is what it points to. On Windows pass target_is_directory=True for folders and enable Developer Mode.