What is ln

ln creates links between files. A link is an additional name pointing to the same data. Linux supports two kinds: hard links and symbolic links (symlinks).

Hard links vs symbolic links

To understand the difference, it helps to know that Linux files have two parts: an inode (metadata + pointer to data) and the file data itself. A filename is just a pointer to an inode.

Hard link — a second filename pointing to the same inode:

  • Both names are equal; neither is "the original"
  • Deleting one name leaves the other intact — the data survives until the last name is removed
  • Cannot span different filesystems
  • Cannot point to directories

Symbolic link — a special file that contains a path to another file:

  • Deleting the target breaks the symlink (dangling link)
  • Can cross filesystems
  • Can point to directories
  • Shows as l in ls -la

Create a symbolic link

ln -s target link_name

Examples:

ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/mysite
ln -s /opt/myapp/bin/myapp /usr/local/bin/myapp
ln -s ~/dotfiles/.bashrc ~/.bashrc

Create a hard link

ln target link_name

Example:

ln report.pdf report-backup.pdf

Both files now share the same inode. Changes to either are visible in both.

Link a directory (symlink only)

ln -s /data/media /home/user/media

Hard links to directories are not allowed (except for . and .. maintained by the kernel).

Verify links

ls -la

A symlink shows as:

lrwxrwxrwx 1 user user 20 Jul  7 10:00 myapp -> /opt/myapp/bin/myapp

Check what a symlink points to:

readlink /usr/local/bin/myapp
readlink -f /usr/local/bin/myapp   # resolve all symlinks, show absolute path

Overwrite an existing link

ln -sf new_target link_name

The -f flag removes the existing link before creating the new one.

Practical examples

Manage Nginx virtual hosts (the Debian/Ubuntu pattern):

ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

Put a script on your PATH without moving it:

ln -s ~/scripts/deploy.sh /usr/local/bin/deploy

Keep dotfiles in a version-controlled directory:

ln -s ~/dotfiles/.vimrc ~/.vimrc
ln -s ~/dotfiles/.bashrc ~/.bashrc

Switch between Python versions:

ln -sf /usr/bin/python3.12 /usr/local/bin/python3

See also

man ln, readlink(1), stat(1) — check inode numbers with stat filename to confirm two names share the same inode.

  • Created: May 16, 2007
  • Last edited: July 7, 2026