The ln command in Linux
ln creates links: additional names for existing files. A symbolic link (symlink, ln -s) is a small pointer to a path — the everyday kind, used for "current version" pointers, config switching and putting tools on the PATH. A hard link is a second directory entry for the same underlying data; it only works within one filesystem and cannot point to directories.
How ln works
A filename is not the file. The file is the inode — the metadata plus data blocks — and names are directory entries pointing at it. A hard link is simply a second entry pointing at the same inode: both names are equally "the real file", the inode's link count says how many exist, and the data lives until the count hits zero. This is also why hard links cannot cross filesystems (inode numbers are per-filesystem) nor point at directories (the tree must stay a tree).
A symbolic link is a different creature: a tiny file whose content is a path, resolved fresh every time it is traversed. That indirection buys everything hard links cannot do — crossing filesystems, linking directories, pointing at things that do not exist yet — at the price of breakability: move or delete the target and the symlink dangles. The deploy-by-symlink pattern exploits the best of both: the switch of a symlink is one atomic rename, so "current" flips between releases with no intermediate state.
Syntax
ln [-s] TARGET LINK_NAME Common options
| Option | What it does |
|---|---|
-s | Create a symbolic link (almost always what you want). |
-f | Replace the link if it already exists. |
-n | With -f, treat an existing symlink to a directory as a file to replace (crucial for "current" pointers). |
(none) | Without -s, ln creates a hard link. |
How to use ln: examples
$ ln -s /opt/app-2.4.1 /opt/app/current The deployment classic: "current" always points at the active release; switching versions is one atomic link change.
$ ln -s ~/dotfiles/.vimrc ~/.vimrc Keep real configs in a git repo and symlink them into place.
$ ln -sfn /opt/app-2.4.2 /opt/app/current Update an existing "current" pointer safely: -f replaces, -n avoids descending into the old target.
$ ls -l /opt/app Symlinks show as: current -> /opt/app-2.4.2, with type "l" in the first column.
$ readlink -f /opt/app/current Resolve where a symlink ultimately points.
Real-world use cases for ln
Zero-downtime release switching
Deploys unpack into /opt/app/releases/2026-08-04/, and /opt/app/current is a symlink to the live one. Releasing = ln -sfn to the new directory: one atomic operation, instant rollback by pointing back. This pattern underlies Capistrano-style deployment everywhere.
Dotfiles under version control
Keep the real .vimrc, .gitconfig and .bashrc in a git repo and symlink them into $HOME. Every machine gets ln -s ~/dotfiles/.vimrc ~/.vimrc once, and from then on git pull updates your configuration everywhere.
Pro tips and common mistakes
- Argument order trips everyone: ln -s TARGET LINKNAME — the real thing first, the new name second. Same order as cp.
- Updating a symlink to a directory needs -n: ln -sfn newtarget link. Without it, the link is created INSIDE the old target.
- Prefer absolute targets for links that scripts follow; relative targets break when the link is moved.
- find -L dir -type l lists broken symlinks — a useful health check after big moves or restores.
Frequently asked questions about ln
What is the difference between a symbolic and a hard link?
A symlink stores a path and breaks if the target moves; it can cross filesystems and point at directories. A hard link is another name for the same data blocks: the file survives until every hard link is deleted, but links cannot cross filesystems or reference directories.
Why is my symlink broken?
Its target was moved or deleted, or the link was created with a relative path that only resolved from the original location. ls -l shows the stored target; readlink -f shows what it resolves to.
Which order do the arguments go in?
Same as cp: real thing first, new name second — ln -s target link_name. If you get it backwards you create a link named after your target sitting in the wrong place.
Related commands
List the contents of a directory, with options for hidden files, long format, sorting and more.
cpCopy files and whole directory trees, preserving attributes when needed.
findLocate files anywhere in a directory tree by name, type, size, date — and act on them.