Two files with different names but the same file on disk. Or a link pointing to a folder elsewhere in the filesystem that looks like a regular directory. Both are links — and in Linux there are two fundamentally different kinds. Here is how they differ and when to use each.
Hard Link vs Symbolic Link: The Core Difference
Every file on disk has a unique number — an inode. It is an identifier in the filesystem table that the actual data is tied to. A filename in a directory is just a pointer to an inode.
A hard link is a second (or third, or tenth) name for the same inode. Delete the 'original' — the data goes nowhere as long as at least one name pointing to that inode exists.
A symbolic link (symlink) is a separate file that stores a path to another file or directory. Delete the original — the symlink becomes broken and leads nowhere.
Check inode numbers:
ls -li
A hard link and its original share the same inode number. A symlink has its own separate inode.
Hard Link
Create a hard link — a second name for a file:
ln file1.txt file2.txt
file1.txt and file2.txt are now the same file. Changing content through either name affects both. Deleting one name does not touch the data — it disappears only when all names are removed.
Hard links only work within the same filesystem — you cannot hard-link a file from another partition or network share. Hard links to directories are not allowed (technically possible as root, but it breaks the directory tree structure).
Symbolic Link
Create a symlink to a file:
ln -s /path/to/file1.txt /path/to/link.txt
Symlink to a directory:
ln -s /var/www/mysite /home/user/mysite
After this, accessing /home/user/mysite transparently works as accessing /var/www/mysite.
Symlinks cross filesystem boundaries — you can link to a file on another partition or external drive. For directories, symlinks are almost exclusively what gets used.
Absolute vs Relative Path in a Symlink
A symlink stores a path — and that path can be absolute or relative.
Absolute path — works from anywhere but breaks if files move to a different location:
ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/mysite
Relative path — the symlink stores a path relative to its own location. Useful when the entire directory structure moves together:
cd /etc/nginx/sites-enabled
ln -s ../sites-available/mysite mysite
Check where a symlink points:
readlink -f /etc/nginx/sites-enabled/mysite
Overwrite an Existing Link: the -f Flag
If the target already exists, ln will refuse to create the link. The -f flag deletes the existing file first, then creates the link:
ln -sf /path/to/new_target existing_link
The -sf combination is the standard for updating symlinks in scripts.
Show What Happened: the -v Flag
ln -sv /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/mysite
The -v flag prints each created link. Useful in scripts where visibility into what happened matters.
Real-World Scenarios
Nginx: activating virtual hosts. On Debian and Ubuntu, site configs live in sites-available and are activated via symlinks in sites-enabled:
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
Deactivate a site — delete the symlink without touching the config:
sudo rm /etc/nginx/sites-enabled/mysite
Multiple Python or Node versions. Quickly switch the default version:
sudo ln -sf /usr/bin/python3.11 /usr/local/bin/python
Centralized log access. If an application writes logs to a non-standard folder, a symlink from /var/log/ makes it visible to centralized monitoring:
sudo ln -s /opt/myapp/logs/app.log /var/log/myapp.log
Find Broken Symlinks
A symlink becomes broken if the original file is deleted or moved. Find all broken symlinks in a directory:
find /etc/nginx/sites-enabled -xtype l
-xtype l finds symlinks pointing to nonexistent targets.
Quick Reference
| Task | Command |
|---|---|
| Hard link | ln file.txt link.txt |
| Symbolic link | ln -s /source /link |
| Symlink to directory | ln -s /source/dir /link/dir |
| Overwrite existing | ln -sf /source /link |
| With output | ln -sv /source /link |
| Where does a symlink point | readlink -f /link |
| Check inodes | ls -li |
| Find broken symlinks | find /path -xtype l |