Both let you refer to "the same file" from two different paths, but they work in fundamentally different ways, with different tradeoffs - mixing them up leads to confusing surprises, especially when deleting or moving files.

Inodes, briefly

Every file's actual data and metadata (permissions, owner, size, timestamps) live in a structure called an inode, identified by an inode number, not by its filename. A directory entry is just a mapping from a name to an inode number. See it directly:

ls -li /etc/hostname
131074 -rw-r--r-- 1 root root 12 Jan  2 10:00 /etc/hostname

That first number, 131074, is the inode number.

Hard links: another name for the same inode

ln original.txt hardlink.txt
ls -li original.txt hardlink.txt
131074 -rw-r--r-- 2 root root 12 Jan  2 10:00 hardlink.txt
131074 -rw-r--r-- 2 root root 12 Jan  2 10:00 original.txt

Same inode number, and the link count (the 2 right after permissions) shows two names now point to it. There's no "original" and "copy" once this is done - both names are equally real, editing either changes the same underlying data, and the data isn't actually deleted until every hard link to it is removed.

Hard links have real limitations: they can't cross filesystem boundaries (an inode number only means something within its own filesystem - see Mounting and fstab), and most systems don't allow hard-linking directories at all, to avoid creating loops in the directory tree.

Symbolic links: a pointer to a path

ln -s /etc/nginx/sites-available/mysite.conf mysite-enabled.conf
ls -li mysite-enabled.conf
131099 lrwxrwxrwx 1 root root 42 Jan  2 10:00 mysite-enabled.conf -> /etc/nginx/sites-available/mysite.conf

A different inode entirely, of type l (symlink), whose "content" is just the target path as text. This is exactly the mechanism Nginx and Apache use for enabling sites (sites-available holds the real config, sites-enabled holds symlinks into it).

Consequences of being a path rather than an inode reference:

  • Works across filesystems, and can even point to a path that doesn't exist yet or no longer exists (a "dangling" symlink)
  • Deleting the target leaves a broken link behind - the link itself still exists, it just points nowhere
  • Deleting the symlink doesn't touch the target at all
  • A relative-path symlink (ln -s ../shared/file.txt link) resolves relative to the symlink's own location, not your current directory, which can be surprising if you move the symlink

Choosing between them

Hard link Symbolic link
Crosses filesystems No Yes
Can target a directory No (generally) Yes
Survives target being deleted N/A - it is the data No - becomes dangling
What ls -l shows Identical to the original Shows -> target explicitly

In practice, symbolic links are the default choice for most everyday use - configuration shortcuts, version "current" pointers, linking a binary into /usr/local/bin. Hard links show up more in specialized cases like backup tools that use them to avoid duplicating unchanged files between snapshots.

Finding links

find / -xdev -xtype l                # broken symlinks (target doesn't exist)
find / -xdev -samefile original.txt  # every hard link to a given inode