One file, two names: pulling on the seam
The first guide in this rung planted a small seed and promised it would grow: a name and a file are two separate things, joined by a directory. The directory entry holds a human name, while the file's real attributes and the addresses of its bytes live somewhere else — on a Unix-style system, in the inode. The directory does nothing more glamorous than pair a name with an inode number. That separation is so quiet you can read past it, but it is the whole foundation of this guide. If a name is just an arrow into an inode, then nothing stops two arrows from aiming at the same inode.
When two directory entries point at one inode, each name is a real, first-class name for the file — neither is the 'original' and neither is a 'copy.' This is a hard link, and the word link is exactly the point: you are linking a second name onto an existing file, not duplicating its bytes. The other kind, a symbolic link (also called a soft link), takes a completely different route: instead of pointing at the inode, it is a separate tiny file whose entire contents are a text path like /home/ana/essays/draft.txt. The rest of this guide is the story of those two routes and why, most days, you cannot tell them apart — until the one day it matters intensely.
The hard link: a second arrow at the same inode
Run `ln target name` and the OS does something refreshingly literal: it adds one new entry to a directory, pairing your chosen name with the same inode number the target already uses. No bytes are copied; no new inode is created. Afterward there are two names but exactly one file, and reading or writing through either name touches the identical bytes — change the file under one name and the change is instantly visible under the other, because there is only one file to change. The two names are genuinely equal: the file system itself cannot tell you which one was made first.
If two names share one file, a hard question follows: when you delete one name, do the bytes go away? The inode answers this with a number it carries called the link count — simply how many directory entries point at it. Make a hard link and the count goes up by one; remove a name and it goes down by one. The data is freed only when the count hits zero, that is, when the very last name is gone. So deleting a hard-linked name is not 'deleting the file' — it is removing one name and decrementing the count. As long as another hard link survives, the bytes survive untouched.
The symbolic link: a tiny file that holds a path
Run `ln -s target name` instead — note the -s, for symbolic — and you get something structurally different. The OS creates a brand-new file, with its own inode, marked with a special file type meaning 'I am a symlink.' Its contents are not your data; they are just the text of the path you named, sitting there like a written-down address. When you later open the symlink, the OS reads that stored path and follows it to wherever it leads, a step called resolution. A symlink is, in the most literal sense, a signpost: it does not contain the destination, it points the way to it by name.
Because a symlink stores a name rather than an inode, two consequences fall straight out — and they are exactly where it earns its keep. First, the path it stores can name a target on a totally different file system, so a symlink can cross file systems freely, and it can even point at a directory, not just a regular file. Second, and more sobering: the target it names might not exist. Move the target, rename it, or delete it, and the symlink keeps pointing at a path that now leads nowhere. This is a dangling (broken) symlink — the signpost still stands, but the place it points to is gone, and trying to open it fails with an error like 'no such file.'
Seeing the difference: inodes and link counts
Abstract talk of arrows and signposts gets sharp the moment you look at real inode numbers and link counts. Picture a file draft.txt living at inode 1733 with a link count of 1. Make a hard link essay.txt to it: now both names sit in the directory pointing at inode 1733, and that inode's link count reads 2. List them and they are indistinguishable — same inode, same size, same bytes, two equal names. Now instead make a symbolic link shortcut.txt: it gets its own fresh inode (say 1899), its link count stays at 1, and its size is just the length of the stored path string. The diagram below freezes both pictures side by side.
HARD LINK (ln draft.txt essay.txt)
directory: inode 1733 (link count = 2)
draft.txt -> 1733 ----\
essay.txt -> 1733 ----+----> [ size, owner, perms ] -> DATA BLOCKS
one file, two equal names
SYMLINK (ln -s draft.txt shortcut.txt)
directory: inode 1733 (link count = 1)
draft.txt -> 1733 --------> [ size, owner, perms ] -> DATA BLOCKS
shortcut.txt -> 1899 (symlink)
|
+-- inode 1899 holds the TEXT "draft.txt" (a stored path)
open(shortcut.txt) -> read path -> follow to 1733Two hard limits on hard links fall out of this same picture, and both come from the inode being a within-one-filesystem thing. A hard link cannot cross file systems, because inode 1733 only means something inside its own file system — a directory entry on another disk has no way to point at it. And on almost every system you usually cannot hard-link a directory: doing so could weave loops into the directory tree, which would trap programs walking it in endless circles and snarl the link-count accounting. Symlinks dodge both limits precisely because they store a path, not an inode — which is also exactly why they can dangle.
Which one, when?
The choice is not a matter of taste; each link's mechanics decide what it is good for. Reach for a hard link when you want several names that are truly the same file on the same disk, with no fragile pointer that can break — for example, a backup name that must keep the data alive even if the original name is removed, since the bytes live until the link count reaches zero. Reach for a symbolic link when you need to point across file systems, point at a directory, or make a friendly shortcut whose target you might later swap out — for instance, a name like 'current' that you re-point from one versioned folder to the next.
- Need the same file under two names on one disk, with no breakable pointer and no copied bytes? Use a hard link: `ln target name`.
- Need to span two file systems, or point at a directory, or keep a shortcut you can re-aim later? Use a symbolic link: `ln -s target name`.
- Deleting a name? With a hard link the data lives on until the last link is gone; with a symlink, deleting the target leaves the symlink dangling.