Symlinks vs Hard Links Explained: The ln Command and How Links Actually Work
The ln command creates links, and Linux has two fundamentally different kinds. Confusing them leads to broken references, mysterious disk usage, and backup scripts that copy the same data twice. The distinction comes down to what a link actually points at.
Inodes: the thing being linked
Every file on a Linux filesystem is really an inode: a structure holding the file’s data location, permissions, ownership, and timestamps. Notably absent from the inode is the filename. Names live in directories, which are just tables mapping names to inode numbers.
A “file” as you normally think of it is therefore a directory entry pointing at an inode. That indirection is what makes two kinds of links possible.
Hard links: another name for the same inode
A hard link is a second directory entry pointing at the same inode:
echo "hello" > original.txt
ln original.txt copy.txt
ls -li original.txt copy.txt
The -i flag shows inode numbers, and both names show the same one. There is no original and no copy; both names are equal citizens referring to identical data. Edit through either name and both reflect the change, because there is only one file.
The inode tracks how many names refer to it, the link count shown in the second column of ls -l. Deleting a name just decrements the count; the data is only freed when the count hits zero and no process holds the file open. This is why you can delete a busy log file and the disk space does not come back until the process writing to it closes or is restarted.
Hard links carry two restrictions: they cannot cross filesystems, since inode numbers only mean something within one filesystem, and they cannot point at directories, which would allow loops in the tree.
Symlinks: a file containing a path
A symbolic link is a different beast entirely: a tiny special file whose content is a path.
ln -s /var/log/syslog shortcut
ls -l shortcut
# lrwxrwxrwx ... shortcut -> /var/log/syslog
Opening shortcut makes the kernel read the stored path and follow it. That indirection buys flexibility: symlinks cross filesystems freely and point at directories without issue, which is why they are everywhere in practice, from /usr/bin/python3 pointing at a specific interpreter version to systemd enabling services by symlinking unit files.
The cost is fragility. The symlink stores a path, not an identity. If the target moves or is deleted, the symlink still points at the old path and is now broken:
find /etc -xtype l # find broken symlinks
readlink -f shortcut # show the fully resolved target
A relative symlink (ln -s ../config/app.conf link) resolves relative to the directory containing the link, which makes it survive moving the whole tree together, while an absolute symlink survives moving the link but not the target.
The argument order everyone forgets
ln -s TARGET LINKNAME
The existing file comes first, the new name second, same order as cp source dest. If you get it backwards and the target name does not exist yet, you create a symlink pointing at nothing. When the second argument is an existing directory, the link is created inside it with the target’s basename.
Choosing between them
Use a symlink when you want a visible, flexible pointer: alternative names for versioned files, redirecting a config path, or making a directory appear somewhere else. The link being distinguishable from the target is usually a feature; tools and humans can see it is a pointer.
Hard links shine in narrower cases: deduplicating identical files on one filesystem, and snapshot-style backup tools like rsync with --link-dest, which build daily backup trees where unchanged files are hard links to the previous day, costing almost no space. If you have ever wondered how a backup tool stores thirty daily snapshots in barely more space than one, hard links are usually the answer.
What follows links and what does not
Commands differ in how they treat symlinks, and it matters. cp follows symlinks by default and copies the target data; cp -P preserves them as links, and cp -a (archive mode) does too. rm removes the link itself, never the target. rsync copies symlinks as symlinks with -a. tar stores symlinks as symlinks by default but has flags to dereference them. When a script misbehaves around links, check which behavior each tool in the chain defaults to.
Frequently Asked Questions
What is the difference between a symlink and a hard link?
A symlink is a small file containing a path to another file. A hard link is an additional directory entry for the same underlying inode, making it indistinguishable from the original. Symlinks can cross filesystems and point to directories; hard links cannot.
What happens to a symlink when the target is deleted?
The symlink remains but becomes broken, pointing at a path that no longer exists. Attempts to open it fail with a file-not-found error. Hard links keep the data alive instead, since the data is only freed when the last link is removed.
How do I create a symlink?
Run ln -s target linkname. The order trips people up: the real file comes first, the name of the new link second. Without -s, ln creates a hard link.
Why can hard links not point to directories?
Directory hard links could create loops in the filesystem tree, which would break programs that walk directories and complicate the meaning of the parent directory entry. All modern filesystems forbid it; symlinks to directories work fine.
How do I find where a symlink points?
Use readlink -f linkname for the fully resolved target, or ls -l which displays the link target after an arrow.
How can I tell how many hard links a file has?
The second column of ls -l is the link count. A regular file with a count above 1 has additional hard links somewhere on the same filesystem. find / -samefile yourfile locates them.