rubyguides

Kernel#require_relative

require_relative(name) -> true or false

require_relative loads an external Ruby file using a path relative to the file containing the require_relative call, not the current working directory. This makes it ideal for loading local dependencies within a project, gem, or library. Unlike require, which searches the $LOAD_PATH, require_relative resolves the path relative to the directory of the file invoking it.

The method returns true if the file was successfully loaded for the first time, or false if it had already been loaded. This behavior mirrors require, making it easy to prevent duplicate loading of the same module.

That relative lookup keeps small codebases easy to move around. As long as the file layout stays the same, the import paths stay the same too, which cuts down on path churn when a project grows.

It also keeps related files easy to read in context. When you open a file and see a relative path, you can usually tell which companion file it expects without checking global settings or scanning the rest of the load path.

Syntax

require_relative(name) -> true or false

The name parameter can be a string representing a file path (with or without the .rb extension). Ruby automatically appends .rb if the file is not found with the exact name given.

That small convenience is useful in simple projects because the import line stays short and predictable. It also matches the way developers usually think about files on disk: nearby code is loaded from a nearby path.

Parameters

ParameterTypeDescription
nameStringThe relative path to the Ruby file to load, without the .rb extension

Examples

Basic usage

require_relative "helpers"

This is the most direct case. The file sits next to the caller, so the path stays short and the dependency is obvious without needing a long search list. Ruby automatically appends .rb when the file is not found with the exact name given, so require_relative "helpers" resolves to helpers.rb in the same directory.

Loading with output

# helpers.rb
module Helpers
  def self.greet(name)
    "Hello, #{name}!"
  end
end

# main.rb
require_relative "helpers"

puts Helpers.greet("World")
# => Hello, World!

The example shows the usual pattern for project internals: one local file defines a small module, and another file loads it with a relative path. That style keeps the dependency chain easy to follow when the project is still small. As the codebase grows, the same relative pattern scales naturally because the imports follow the file tree instead of a global search path.

Nested directory loading

# lib/utils/math.rb
module Math
  module Operations
    def self.add(a, b)
      a + b
    end
  end
end

# main.rb
require_relative "lib/utils/math"

puts Math::Operations.add(5, 3)
# => 8

Nested paths are still relative to the caller, so the code reads naturally even when the file tree gets deeper. That keeps libraries organized without forcing you to hardcode a root directory into every import. The directory separator in the argument maps directly to the file-system hierarchy, so the path in the code mirrors the folder structure on disk.

Checking if already loaded

result1 = require_relative "helpers"
puts result1
# => true

result2 = require_relative "helpers"
puts result2
# => false

That return value makes it simple to guard one-off setup code or avoid loading the same file more than once. In practice, it behaves much like require, but the lookup stays anchored to the current file. This return-value convention means you can wrap require_relative in a conditional without needing a separate tracking mechanism.

Common Patterns

Loading gem-like library structures:

require_relative "my_app/version"
require_relative "my_app/config"
require_relative "my_app/core"

These grouped imports show how require_relative fits a modular codebase. Each file can describe the part it needs, and the directory layout gives you a simple map to follow. This structure mirrors how gems and larger Ruby projects organize their internals, making the codebase self-documenting through its file layout.

Using dir for more complex paths:

require_relative __dir__ + "/../config/environment"

__dir__ is useful when the relationship is still local but the path is a little deeper. It keeps the call site clear without forcing you to guess at the current working directory. Because __dir__ expands to the directory of the current file at parse time, the resulting path is stable regardless of where the Ruby process was launched.

Conditional loading:

require_relative "debugging" if ENV["DEBUG"]

Conditional loading is a good fit for debugging helpers or optional features. The file only loads when the environment asks for it, which keeps normal runs a little lighter. This pattern is common in Rack middleware and Rails initializers, where environment-specific code should only activate in development or test mode.

Errors

LoadError - file not found:

require_relative "nonexistent_file"
# => LoadError: cannot load such file

LoadError - called from eval:

The require_relative method cannot infer the base path when called from within an eval expression. This is because eval lacks the file context that require_relative needs to resolve relative paths against the calling script.

eval("require_relative helpers")
# => LoadError: cannot infer basepath

ArgumentError:

Calling require_relative without any arguments raises an ArgumentError because the method always expects exactly one argument — the relative path to the file you want to load. Providing more than one argument will also raise this error, so always pass exactly one path string.

require_relative
# => ArgumentError: wrong number of arguments

In practice, require_relative is best for files that live inside the same project tree. If the code needs to be resolved from a broader search path, require is usually the better choice because it follows $LOAD_PATH instead of the local directory.

That rule of thumb keeps the choice simple: use require_relative for close neighbors and require for shared libraries. The distinction helps prevent path surprises once the codebase grows.

See Also