ln — create hard and symbolic links

A link is a name, not a copy. Learn the two flavors — and why using the wrong one breaks on a reboot.

You know cp. You know mv. But the file on disk you have "two copies" of is the same one file wearing two names — and that trick is the whole art of the Linux filesystem.

What it does

ln creates links — extra names that point at an existing file or directory without copying its data. The default is a hard link: a second directory entry sharing the exact same inode (the on-disk block of metadata and data). You can spot hard links because `ls -l` shows the link count (the number after the permissions) and `ls -i` shows the same inode number. The second flavor, `ln -s`, makes a symbolic (soft) link: a tiny pointer file that stores the target's path as text. Symlinks can cross filesystems, point at directories, and even point at things that do not exist yet — hard links are limited to files on the same filesystem.

Why it matters

Links are how you version a config without duplicating it (`ln -s conf/app.ini latest.ini`), how installed binaries appear in your PATH from a central directory (`ln -s /opt/node/bin/node ~/bin/node`), and how Docker and home-manager-style setups make multiple trees share one truth. The moment you grasp that a symlink is just a path-on-a-stick that the kernel resolves on access, a whole class of 'why did mv break it?' bugs stops happening. Hard links are the quieter superpower: the classic backup pattern of linking unchanged files costs no disk and lets you delete a name without losing the data.

Examples

ln -s conf/app.ini latest.ini && ls -l latest.ini
lrwxrwxrwx 1 kmail kmail 12 Sep 18 09:01 latest.ini -> conf/app.ini

Symbolic link to a file. The `->` shows the stored target path. Reading latest.ini resolves through it — the kernel follows the pointer on every access, so editing app.ini is instantly visible through the link.

cat latest.ini
[server]
host = 127.0.0.1
port = 5432

Reading through the symlink is transparent — cat has no idea it is not the real file. This is the 'name as a version' trick: one real config, any number of named views into it.

ln -sf conf/app.ini must_be_link && ls -l must_be_link
lrwxrwxrwx 1 kmail kmail 12 Sep 18 09:01 must_be_link -> conf/app.ini

-f overwrites an existing file or link in place. Without -f, `ln -s` refuses (or errors) if the target name already exists. Careful: -f on a symlink with a trailing slash retargets the directory itself, which surprises people.

ln -s conf/vanished.ini broken && cat broken
cat: broken: No such file or directory

A dangling symlink — the pointer exists but points at nothing. cat fails with 'No such file or directory', which confuses people because the link clearly exists. The file it points to is gone; the link is now a landmine.

find -L /tmp/lntut -type l
/tmp/lntut/broken

find -L follows symlinks while matching, so -type l surfaces every dangling link in the tree. Run this after a move or rm binge to sweep up the dead pointers before they break a backup or a service.

ln orig.txt hard.txt && ls -li orig.txt hard.txt
3994751 -rw-rw-r-- 2 kmail kmail 12 Sep 18 09:01 hard.txt
3994751 -rw-rw-r-- 2 kmail kmail 12 Sep 18 09:01 orig.txt

A hard link: same inode 3994751, link count 2, no -> arrow. These are two names for the SAME data. Editing either name changes both, and deleting one name leaves the data intact under the other.

Flags

FlagMeaning
-s, --symbolicmake a symbolic (soft) link rather than a hard link — the only form that works on directories
-f, --forceremove any existing destination file or link before creating the new one
-n, --no-dereferenceif the destination is a symlink to a directory, treat it as a normal file instead of descending into it
-v, --verboseprint the name of each link created
-t, --target-directorycreate links in the given directory: `ln -s /a /b -t /dir`
no flag (default)create a hard link that shares the source's inode — same filesystem required, no directories, no symlinks
-i, --interactiveask before overwriting an existing destination (good safety net atop -f)

Origin

ln is one of the oldest commands, present at the birth of Unix at Bell Labs in 1971. Hard links come straight from the original filesystem design — an inode with multiple directory entries. Symlinks, the far more useful flavor for everyday work, did not arrive until 1972 with the addition to the filesystem abstraction, and BSD's 4.2 added ln -s in the early 80s. That split still shows: the '-s' flag is the newcomer bolted onto a 50-year-old command.

Why symlinks won

Hard links cannot cross filesystems and cannot link directories, which makes them useless for the two jobs people actually want: aliasing a binary anywhere on the box and pointing at a tree. Symlinks are just path strings, so the kernel resolves them on every access — that is why a symlink to a directory 'works' where a hard link cannot. It also means a symlink is always relative to its own location when the path does not start with '/', which is exactly how `ln -s conf/app.ini latest.ini` stays valid even if both get moved together.

Fun facts

Pros

Cons

Takeaways