What Is a Symbolic Link in Linux?

A symbolic link (symlink or soft link) in Linux is a special file that acts as a pointer to another file or directory. Create one with ln -s target linkname — for example, ln -s /var/log/nginx/access.log ~/logs/nginx_access.log creates a link in your home directory that points to the nginx log file. When you access the symlink, Linux transparently redirects you to the target. Symbolic links can point to files, directories, and even other links, and can cross filesystem boundaries.

The Filesystem’s Shortcuts

Imagine being able to access a file in two different places simultaneously without copying it — the file exists once, but you can reach it from multiple locations. Change it through any path and the change is immediately visible everywhere. That is what symbolic links make possible.

Symbolic links are one of the most useful and most used features in Linux filesystems. Every time you interact with Linux, you are silently using them. The /bin directory on Ubuntu is actually a symbolic link to /usr/bin. The Python interpreter you call as python3 may be a symlink pointing to a specific version. Configuration directories in /etc frequently use symlinks to manage alternative configurations. The entire alternative-versions management system that allows multiple installed versions of a library to coexist uses symlinks extensively.

Beyond their pervasive use within the operating system itself, symlinks are a practical daily tool: creating convenient shortcuts to deeply nested directories, providing stable paths that can be updated to point to new versions, connecting configuration files between locations, and building flexible directory structures that adapt to different environments.

This article explains symbolic links from the ground up — what they are technically, how they differ from hard links, how to create and manage them with the ln command, how to identify them in directory listings, what happens when they break, and the practical patterns where they shine. By the end, you will not only understand what symlinks are but think naturally about when to reach for them.

Understanding Links: How Linux Tracks Files

To understand symbolic links, a foundation in how Linux actually stores files on disk clarifies everything that follows.

Inodes: The True Identity of Files

Every file on a Linux filesystem has an inode — a data structure stored on disk that records everything about the file except its name:

  • File size
  • Timestamps (created, modified, accessed)
  • Owner and group
  • Permission bits
  • The disk blocks where the file’s data is stored
  • A reference count (how many directory entries point to this inode)

The inode has a number — its inode number — but no name. Names live in directory entries, not in inodes. A directory is a special file containing a table that maps filenames to inode numbers.

When you access a file by path — say /home/sarah/document.txt — the kernel:

  1. Looks up home in the root directory’s entry table → finds inode for /home
  2. Looks up sarah in /home‘s entry table → finds inode for /home/sarah
  3. Looks up document.txt in /home/sarah‘s entry table → finds the file’s inode number
  4. Reads the inode to get the file’s data block locations
  5. Returns the file’s data

The filename document.txt is just one entry in one directory table pointing to one inode. This design is what makes multiple names for the same file (links) possible.

Hard Links: Multiple Names for the Same Inode

A hard link is simply another directory entry pointing to an existing inode. After running ln original.txt hardlink.txt, you have two filenames in a directory table, both pointing to the same inode:

/home/sarah/original.txt  ──┐
                            ├──→  Inode #12345 (the actual file data)
/home/sarah/hardlink.txt  ──┘

The inode’s reference count increases to 2. The file data exists once on disk. Both names are completely equivalent — there is no “original” versus “link.” The data persists as long as any hard link to the inode exists.

Hard links are powerful but limited:

  • Cannot span filesystems: an inode number is meaningful only within one filesystem; a hard link must be on the same filesystem as its target
  • Cannot link directories: hard links to directories are not permitted (they would create loops in the filesystem graph that fsck and other tools cannot handle)
  • No visual indication: there is no way to look at a file and know whether it is a hard link or a “regular” file — both look identical in ls

Symbolic Links: A Different Approach

A symbolic link (symlink, soft link) takes a completely different approach. It is an actual, separate file — with its own inode — whose content is a text string: the path to the target.

/home/sarah/link.txt  ──→  Inode #99999 (a symlink file containing "/home/sarah/original.txt")
                                                    ↓
                           Inode #12345 (the actual file data)

When the kernel encounters a symlink during path resolution, it reads the path string from the symlink’s inode and continues resolution from there — transparently redirecting to the target. This redirection is called dereferencing the symlink.

Because a symlink stores a path string (not an inode reference), it can:

  • Point to anything, on any filesystem
  • Point to directories, not just files
  • Cross filesystem boundaries (a symlink on /dev/sda1 can point to a file on /dev/sdb1)
  • Point to non-existent targets (a dangling or broken symlink)
  • Be identified visually — ls -la shows symlinks with l type and → arrow

The trade-off: a symlink adds one level of indirection (the kernel follows the pointer). And unlike hard links, deleting the target breaks the symlink.

Creating Symbolic Links: The ln Command

The ln command creates links. Without flags it creates hard links; with -s it creates symbolic links.

Basic Syntax

ln -s target linkname
  • target — the path the symlink will point to (what you want to access)
  • linkname — the name and location of the symlink file you are creating

Order matters: target comes first, linkname second. This is the same order as cp source destination — you are creating linkname as a pointer to target.

Creating a Symlink to a File

$ ln -s /var/log/nginx/access.log ~/logs/nginx_access.log
$ ls -la ~/logs/
lrwxrwxrwx 1 sarah sarah 29 Feb 18 11:00 nginx_access.log -> /var/log/nginx/access.log

The l at the start of lrwxrwxrwx indicates a symbolic link. The -> shows what the symlink points to. The permissions shown (rwxrwxrwx) are the symlink’s own permissions — the target’s permissions govern actual access.

Creating a Symlink to a Directory

$ ln -s /home/sarah/projects/current_project ~/work
$ ls -la ~/ | grep work
lrwxrwxrwx 1 sarah sarah 37 Feb 18 11:05 work -> /home/sarah/projects/current_project

$ cd ~/work         # This works — bash follows the symlink
$ pwd
/home/sarah/work    # Note: pwd shows the logical path through the symlink

Relative vs. Absolute Symlink Paths

Symlinks can use either absolute paths or relative paths. The choice matters for portability.

Absolute symlink (the target path starts with /):

$ ln -s /etc/nginx/nginx.conf ~/nginx.conf

The symlink always points to /etc/nginx/nginx.conf regardless of where the symlink is located.

Relative symlink (the target path is relative to the symlink’s location):

$ cd /etc/nginx/sites-enabled
$ ln -s ../sites-available/mysite.conf mysite.conf

The path ../sites-available/mysite.conf is interpreted relative to /etc/nginx/sites-enabled/. This symlink would break if moved to a different directory but works correctly in its intended location.

When to use relative paths: When the symlink and its target will always be moved together (same relative position in the directory tree). Relative symlinks are more portable for self-contained directory structures.

When to use absolute paths: When pointing to a fixed system location that will not move. Easier to understand and less likely to break unexpectedly.

The -v Flag: Verbose Output

$ ln -sv /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/mysite.conf
'/etc/nginx/sites-enabled/mysite.conf' -> '/etc/nginx/sites-available/mysite.conf'

The -v flag shows what was created — useful for confirming the link was made correctly.

Creating a Symlink That Overwrites an Existing One

If a symlink at linkname already exists and you want to update where it points:

$ ln -sf new_target existing_linkname

The -f (force) flag removes the existing link before creating the new one. Without -f, ln reports “File exists” and does nothing.

Identifying Symbolic Links

In ls Output

$ ls -la /etc/alternatives/ | head -10
lrwxrwxrwx 1 root root  13 Feb 18 09:00 awk -> /usr/bin/gawk
lrwxrwxrwx 1 root root  15 Feb 18 09:00 editor -> /usr/bin/nano
lrwxrwxrwx 1 root root  19 Feb 18 09:00 python3 -> /usr/bin/python3.12
lrwxrwxrwx 1 root root  22 Feb 18 09:00 python -> /usr/bin/python3.12

Every line beginning with l is a symbolic link. The -> shows the target path. The size shown (13, 15, 19, etc.) is the length of the path string stored in the symlink — not the size of the target file.

Using file to Identify a Symlink

$ file /etc/alternatives/python3
/etc/alternatives/python3: symbolic link to /usr/bin/python3.12

$ file /usr/bin/python3.12
/usr/bin/python3.12: ELF 64-bit LSB pie executable, x86-64

Using find to Locate Symlinks

$ find /etc -type l               # Find all symlinks in /etc
$ find /etc -type l -name "*.conf"  # Find symlinks with .conf extension
$ find ~ -type l                  # Find all symlinks in your home directory

Checking What a Symlink Points To

$ readlink /etc/alternatives/python3
/usr/bin/python3.12

$ readlink -f /etc/alternatives/python3    # Follow all symlinks to final target
/usr/bin/python3.12

$ readlink -f ~/work    # Resolve symlink to real path
/home/sarah/projects/current_project

readlink -f follows the entire chain of symlinks and returns the absolute real path. Useful for scripts that need the actual file location regardless of how many symlinks are involved.

Broken Symlinks: When the Target Disappears

A symbolic link stores a path — if the target at that path no longer exists, the symlink becomes broken (also called a dangling symlink). The symlink file itself still exists but is useless.

$ ln -s /tmp/temporary_file.txt ~/mylink.txt
$ rm /tmp/temporary_file.txt    # Delete the target

$ ls -la ~/mylink.txt
lrwxrwxrwx 1 sarah sarah 22 Feb 18 11:15 mylink.txt -> /tmp/temporary_file.txt

$ cat ~/mylink.txt
cat: /home/sarah/mylink.txt: No such file or directory

In many terminal environments with color support, broken symlinks are displayed in a distinct color (often red or flashing) to make them visually obvious.

Finding Broken Symlinks

$ find /etc -type l ! -e          # Find symlinks that do not resolve to an existing file
$ find ~ -xtype l                 # Another approach: find symlinks with broken targets

-xtype l matches files that are symlinks whose target does not exist or cannot be followed.

Removing Broken Symlinks

$ find /path -xtype l -delete     # Delete all broken symlinks

Or more carefully, review them first:

$ find /path -xtype l -print      # List broken symlinks
$ find /path -xtype l -exec rm {} \;   # Delete after reviewing

Removing Symbolic Links

Remove a symlink with rm or unlink:

$ rm ~/mylink.txt           # Removes the symlink, NOT the target
$ unlink ~/mylink.txt       # Equivalent, arguably clearer intent

Critical: rm and unlink remove the symlink file itself, not the target it points to. The target file is completely unaffected.

One common mistake: adding a trailing slash when using rm on a symlink to a directory:

$ rm -rf linktodir/     # DANGER: removes contents of the TARGET directory
$ rm linktodir          # Safe: removes only the symlink
$ rm -rf linktodir      # Also safe: -rf on a symlink itself just removes the symlink

The trailing slash causes the shell to dereference the symlink and operate on the directory it points to. Without the trailing slash, rm operates on the symlink itself.

Symbolic Links vs. Hard Links: When to Use Each

Feature Symbolic Link Hard Link
Can cross filesystems Yes No
Can link directories Yes No (generally)
Shows as link in ls Yes (l type, -> arrow) No (indistinguishable from regular files)
Breaks if target deleted Yes (dangling symlink) No (data persists while any link exists)
Can point to non-existent target Yes (creates dangling link) No (target must exist)
Inode count Separate inode from target Same inode as target
Use cases Shortcuts, version management, cross-filesystem Redundant names within same filesystem

Use symbolic links for: shortcuts, pointing to directories, cross-filesystem references, version management (current → v2.1), configuration management, anything where the target might be replaced or moved.

Use hard links for: creating multiple equivalent names for a file within the same filesystem, backup systems that use hard link deduplication (like rsync --link-dest), situations where the link should survive deletion of the “original.”

In practice, symbolic links are used far more frequently. Hard links serve niche use cases, primarily in backup and archival systems.

Practical Uses of Symbolic Links

1. Version Management: Pointing “current” to a Specific Version

Software often gets installed in versioned directories. A symlink named current points to whichever version is active:

/opt/nodejs/
├── v18.20.0/
├── v20.11.0/
└── current -> v20.11.0/
$ ls /opt/nodejs/
current  v18.20.0  v20.11.0

$ /opt/nodejs/current/bin/node --version
v20.11.0

# Upgrade by updating the symlink
$ sudo ln -sf /opt/nodejs/v20.11.0 /opt/nodejs/current

Scripts and configurations that reference /opt/nodejs/current/bin/node automatically use the current version without modification.

2. The Nginx/Apache Sites Pattern

Web server configurations use symlinks to manage enabled vs. available configurations:

/etc/nginx/
├── sites-available/       ← All configurations live here
│   ├── mysite.conf
│   ├── api.conf
│   └── staging.conf
└── sites-enabled/         ← Symlinks to active configurations
    ├── mysite.conf -> ../sites-available/mysite.conf
    └── api.conf -> ../sites-available/api.conf

Enable a site:

$ sudo ln -s /etc/nginx/sites-available/staging.conf /etc/nginx/sites-enabled/

Disable a site (without deleting the configuration):

$ sudo rm /etc/nginx/sites-enabled/staging.conf

This pattern separates “all configurations I have written” from “configurations currently active” — making it easy to enable and disable without editing or moving files.

3. Dotfile Management

Developers who maintain their configuration files (dotfiles) in a git repository use symlinks to put those files in their expected locations:

~/dotfiles/
├── .bashrc
├── .vimrc
└── .config/nvim/init.vim

# Create symlinks from home directory to the repo
$ ln -sf ~/dotfiles/.bashrc ~/.bashrc
$ ln -sf ~/dotfiles/.vimrc ~/.vimrc

Now ~/.bashrc is a symlink to ~/dotfiles/.bashrc. Editing either path edits the same file. The git repository at ~/dotfiles tracks all changes, and setting up a new machine just requires cloning the repo and running the symlink-creation script.

4. Accessing Deeply Nested Directories

A symlink creates a convenient shortcut to a frequently accessed location:

$ ln -s ~/projects/client_work/2026/big_project/src/components ~/components
$ cd ~/components    # Instead of cd ~/projects/client_work/2026/big_project/src/components

5. /bin → /usr/bin: System-Level Compatibility

On modern Ubuntu and Fedora systems, /bin is a symlink to /usr/bin:

$ ls -la /bin
lrwxrwxrwx 1 root root 7 Jan 15 2023 /bin -> usr/bin

Scripts and programs that reference /bin/bash still work because the symlink transparently redirects to /usr/bin/bash. This consolidation of /bin and /usr/bin into one directory was made possible entirely by symlinks.

6. The update-alternatives System

Ubuntu and Debian use a symlink-based system to manage multiple installed versions of tools:

$ ls -la /usr/bin/python*
lrwxrwxrwx  python3 -> python3.12
-rwxr-xr-x  python3.12
-rwxr-xr-x  python3.11

$ sudo update-alternatives --config python3
There are 2 choices for python3:
  Selection    Path                Priority   Status
  1            /usr/bin/python3.12  100       auto mode
* 2            /usr/bin/python3.11   50       manual mode

Press Enter to keep current choice, or enter selection number:

update-alternatives manages a chain of symlinks — changing your “default python3” updates a symlink, not the actual binaries.

Working with Symlinks in Commands

Several common Linux commands behave differently with symlinks:

cp: Copying Symlinks

$ cp symlink.txt destination/     # Copies the TARGET file, not the symlink
$ cp -P symlink.txt destination/  # Copies the symlink itself (preserves it)
$ cp -a source/ destination/      # Archive mode: preserves symlinks

mv: Moving Symlinks

$ mv symlink.txt newlocation/     # Moves the symlink (the pointer), not the target

Moving a symlink with an absolute path keeps the pointer working (the target path is unchanged). Moving a symlink with a relative path may break it if the relative path no longer resolves correctly.

ls with Symlinks

$ ls -l symlink.txt               # Shows symlink properties and target
$ ls -lL symlink.txt              # Dereferences symlink, shows target's properties
$ ls -la directory/               # Shows directory's own properties
$ ls -laL directory/              # Dereferences directory symlink, shows target's contents

du and df with Symlinks

$ du -sh symlink_to_dir/          # Counts the TARGET directory's size (follows symlink)
$ du -sh --no-dereference symlink_to_dir   # Counts only the symlink file itself

Quick Reference: Symbolic Link Commands

Task Command
Create a symlink ln -s target linkname
Create with verbose output ln -sv target linkname
Force overwrite existing symlink ln -sf new_target linkname
Remove a symlink rm linkname or unlink linkname
Show symlink target readlink linkname
Resolve full real path readlink -f linkname
List symlinks in directory ls -la (look for l type)
Find all symlinks in path find /path -type l
Find broken symlinks find /path -xtype l
Delete broken symlinks find /path -xtype l -delete
Copy symlink itself cp -P symlink destination
Check if path is a symlink [ -L path ] && echo "is symlink"

Conclusion: Symlinks as Filesystem Architecture

Symbolic links are one of the most elegant features of the Unix/Linux filesystem model. They enable a flexibility that would otherwise require copying files, maintaining multiple versions, or creating rigid directory structures. The ability to point any location in the filesystem to any other location — on any filesystem, across any directory boundary — is a simple mechanism with profound implications for system design.

You encounter symlinks constantly in Linux even without noticing: /bin pointing to /usr/bin, Python version management, nginx site configuration, shared library naming (libssl.so pointing to libssl.so.3.0.2). They are the filesystem’s way of saying “what you see here is actually over there.”

Understanding symlinks — what they are, how to create them, how to identify them, when they break, and the practical patterns they enable — turns you from someone who encounters them as confusing filesystem anomalies into someone who uses them as deliberate architectural tools. They are simple to create with ln -s, visible in ls -la output, inspectable with readlink, and powerful enough to underpin major system management patterns. Add symlinks to your Linux toolkit and you gain a new dimension of filesystem flexibility.

Hot this week

What Are Snap, Flatpak, and AppImage Packages?

Learn what Snap, Flatpak, and AppImage are, how universal Linux packages work, their differences, pros and cons, and when to use each format for installing software.

How to Change Your Desktop Environment in Linux

Learn how to install and switch desktop environments in Linux — from GNOME to KDE Plasma, XFCE, MATE, Cinnamon, and more. Includes installation steps and how to choose the right DE.

Understanding Linux System Directories: What Goes Where?

Learn the Linux filesystem hierarchy — what each directory like /etc, /var, /usr, /home, /tmp, /proc, and /dev contains and why the system is organized this way.

How to Mount and Unmount Drives in Linux

Learn how to mount and unmount drives, USB drives, and partitions in Linux using the mount command, /etc/fstab for persistent mounts, and how to safely eject external drives.

Understanding the Linux Man Pages: Your Built-in Documentation

Learn how to use Linux man pages to look up any command, understand its options, and navigate the built-in documentation system. Includes man, info, apropos, and whatis.

Topics

What Are Snap, Flatpak, and AppImage Packages?

Learn what Snap, Flatpak, and AppImage are, how universal Linux packages work, their differences, pros and cons, and when to use each format for installing software.

How to Change Your Desktop Environment in Linux

Learn how to install and switch desktop environments in Linux — from GNOME to KDE Plasma, XFCE, MATE, Cinnamon, and more. Includes installation steps and how to choose the right DE.

Understanding Linux System Directories: What Goes Where?

Learn the Linux filesystem hierarchy — what each directory like /etc, /var, /usr, /home, /tmp, /proc, and /dev contains and why the system is organized this way.

How to Mount and Unmount Drives in Linux

Learn how to mount and unmount drives, USB drives, and partitions in Linux using the mount command, /etc/fstab for persistent mounts, and how to safely eject external drives.

Understanding the Linux Man Pages: Your Built-in Documentation

Learn how to use Linux man pages to look up any command, understand its options, and navigate the built-in documentation system. Includes man, info, apropos, and whatis.

How to View Running Processes in Linux

Learn how to view and manage running processes in Linux using ps, top, htop, pgrep, and pstree. Understand process states, PIDs, CPU/memory usage, and how to find and kill processes.

What Is BASH? Understanding the Linux Shell

Learn what Bash is, how the Linux shell works, the difference between the terminal and the shell, Bash features every user should know, and how to customize your shell environment.

How to Check Your Linux System Information

Learn how to check Linux system information including OS version, kernel, CPU, RAM, disk space, network, and hardware details using essential terminal commands.

Related Articles

Popular Categories