Symbolic Links

A symbolic link (sometimes called a symlink or soft link) is a filesystem entry that stores a filesystem path. The stored path refers to a target filesystem entry, which may or may not exist. Further, the stored path need not even be a valid path.

Most Ruby methods that deal with filesystem paths “follow” symbolic links; that is, if the path refers to a symlink, the method does not operate on the entry at that path, but instead operates on the path stored in the symlink:

File.symlink('README.md', 'foo')
File.read('foo').size # => 3463  # Size of README.md, not foo.
File.delete('foo')

Each of these methods creates a symlink:

If the target path is itself a symlink, that symlink is not followed.

Examples:

# Symlink for a file.
File.symlink('README.md', 'foo')
# Symlink for another symlink.
File.symlink('foo', 'bar')
File.read('README.md').size      # => 3463
File.read('foo').size            # => 3463
File.read('bar').size            # => 3463
# Symlink for a directory.
File.symlink('doc/', 'baz')
Dir.entries('doc/').size         # => 33
Dir.entries('baz').size          # => 33
File.unlink('foo', 'bar', 'baz') # Clean up.

lstat

Each of these methods creates a File::Stat object for a filesystem entry:

The object contains information for the entry at the given path, even if that entry is a symlink; i.e., symlinks are not followed.

By contrast, each of the methods File::stat and Pathname#stat do follow symlinks.

Examples:

linkpath = 'foo'
File.symlink('README.md', linkpath)
File::stat(linkpath).size  # => 3469  # Size of file README.md.
File::lstat(linkpath).size # => 9     # Size of symlink linkpath.
File.unlink(linkpath)      # Clean up.

Each of these methods returns whether the entry at a given path is a symlink:

If the entry is a symlink, it is not followed.

Examples:

linkpath = 'foo'
File.symlink('README.md', 'foo')
File.symlink?(linkpath)    # => true
File.symlink?('README.md') # => false
File.symlink?('nosuch')    # => false
File.delete(linkpath)      # Clean up.

Each of these methods returns the path stored in a symlink:

Examples:

linkpath = 'foo'
File.symlink('README.md', 'foo')
File.readlink(linkpath)     # => "README.md"
File.delete(linkpath)       # Clean up.

lchmod

Each of these methods changes the mode of the symlink entry:

These methods are not supported on Windows or Linux (raise NotImplementedError).

lchown

Each of these methods changes the ownership of a symlink entry:

Example:

# Super user; all privileges.
Process.uid # => 0
Process.gid # => 0
# Create regular file and symlink to it.
filepath = 't.tmp'
linkpath = 'foo'
File.write(filepath, '')
File.symlink(filepath, linkpath)
# Capture original statuses.
fstat0 = File.stat(filepath)
lstat0 = File.lstat(linkpath)
fstat0.uid # => 0
fstat0.gid # => 0
lstat0.uid # => 0
lstat0.gid # => 0
# Change owner for the symlink.
File.lchown(1000, 1000, linkpath)
# Capture new statuses.
fstat1 = File.stat(filepath)
lstat1 = File.lstat(linkpath)
# User id and group id for file not changed.
fstat1.uid # => 0
fstat1.gid # => 0
# User id and group id for link changed.
lstat1.uid # => 1000
lstat1.gid # => 1000
# Clean up.
File.delete(filepath, linkpath)

lutime

Each of these methods updates timestamps for a symlink entry:

Example:

filepath = 'README.md'
linkpath = 'foo'
File.symlink(filepath, linkpath)
# Take snapshots of both.
fstat0 = File.stat(filepath)
lstat0 = File.lstat(linkpath)
# Fetch access times and modification times of both.
fstat0.atime    # => 2026-09-03 07:46:04.940377552 -0500
fstat0.mtime    # => 2026-09-01 09:09:28.378987388 -0500
lstat0.atime    # => 2026-09-03 09:14:13.753865727 -0500
lstat0.mtime    # => 2026-09-03 09:14:13.753865727 -0500
# Update access time and modification time of the symlink.
time = Time.now # => 2026-09-03 09:16:42.619702232 -0500
File.lutime(time, time, linkpath)
# Take fresh snapshots of both.
fstat1 = File.stat(filepath)
lstat1 = File.lstat(linkpath)
# Fetch access time and modification time of file (not changed).
fstat1.atime    # => 2026-09-03 07:46:04.940377552 -0500
fstat1.mtime    # => 2026-09-01 09:09:28.378987388 -0500
# Fetch access time and modification time of link (changed).
lstat1.atime    # => 2026-09-03 09:16:52.77029217 -0500
lstat1.mtime    # => 2026-09-03 09:16:42.619702232 -0500
# Clean up.
File.delete(linkpath)

rename

Each of these methods changes the name of an entry (which need not be a symlink):

Examples:

File.symlink('README.md', 'foo')
File.rename('foo', 'bar')
File.symlink?('bar') # => true
File.rename('bar', 'baz')
File.symlink?('baz') # => true
File.delete('baz')   # Clean up.

Each of these methods removes an entry (which need not be a symlink):

Example:

linkpath = 'foo'
File.symlink('README.md', linkpath)
File.unlink(linkpath)

Sometimes it’s necessary to query, modify, or delete a symlink; therefore certain Ruby methods do not follow symlinks, but instead operate directly on the symlinks.

Each method in the table below has a symlink-specific purpose.

Method Name Effect
File::Stat#symlink? Returns whether a path is a symlink.
File::lchmod Changes the mode of the symlink. See Note 1.
File::lchown Changes the ownership of the symlink. See Note 2.
File::lstat Creates a File::Stat object for a link. See Note 3.
File::lutime Updates timestamps for the symlink. See Note 4.
File::readlink Returns the path stored in a symlink.
File::symlink Creates a symlink.
File::symlink? Returns whether a path is a symlink.
FileUtils::ln_s Creates a symlink.
FileUtils::ln_sf Creates a symlink.
FileUtils::ln_sr Creates a symlink.
Pathname#lchmod Changes the mode of the symlink. See Note 1.
Pathname#lchown Changes the ownership of the symlink. See Note 2.
Pathname#lstat Creates a File::Stat object for a link. See Note 3.
Pathname#lutime Updates timestamps for the symlink. See Note 4.
Pathname#make_symlink Creates a symlink.
Pathname#readlink Returns the path stored in a symlink.
Pathname#symlink? Returns whether a path is a symlink.

Notes:

  1. File::chmod and Pathname#chmod follow symlinks before changing the mode.

  2. File::chown and Pathname#chown follow symlinks before changing the ownership.

  3. File::stat and Pathname#stat follow symlinks before creating the File::Stat object.

  4. File::utime and Pathname#utime follow symlinks before updating timestamps.

Other Non-Following Methods

The methods in the table below do not follow symlinks, but instead operate directly on the entry at the path (which may or may not be a symlink).

Method Effect
File::delete Removes the entry.
File::link Creates a hard link.
File::rename Changes the name of the entry.
File::unlink Removes the entry.
FileUtils::link_entry Creates a hard link.
FileUtils::ln (aliased as FileUtils.link) Creates a hard link.
Pathname#rename Changes the name of the entry.
Pathname#unlink (aliased as Pathname#delete) Removes the entry.