Kernel#autoload
autoload(const_name, filename) -> nil The autoload method defers the loading of a Ruby file until a specific constant is actually used. This improves startup time by only loading code when it’s needed.
How it works
When you call autoload, you specify a constant name and a file path. Ruby won’t load the file until something tries to reference that constant. Once loaded, the constant is available just as if you’d required the file.
Practical Examples
Basic Setup
# In some initialization file
autoload :User, 'models/user'
autoload :Product, 'models/product'
# When User is first referenced, models/user.rb is loaded
user = User.find(1) # File loaded here on first use
This pattern is useful when a project has a lot of code but only a small part of it is needed at boot time. The constant stays available to the rest of the program, but the file does not load until the constant is actually touched. That can keep startup work smaller without changing how the constant is referenced later.
File naming conventions
# autoload expects file path, not class name
# This looks for 'models/user.rb'
autoload :User, 'models/user'
# For namespaced classes
autoload :AdminUser, 'models/admin/user'
The file path matters because autoload is driven by the constant name and the location you give it. Clear naming conventions help avoid guesswork, especially in larger codebases where several files may define nearby constants. When the path reflects the constant well, the first load is easier to trace and debug.
Module setup
module Services
autoload :Email, 'services/email'
autoload :Payment, 'services/payment'
autoload :Notification, 'services/notification'
end
# First use loads the file
Services::Email.send_welcome(user)
Module-level autoloading is a nice way to keep related constants grouped together. It works especially well when a namespace acts like a feature boundary, such as a service layer or a plugin area. Each constant can still load on demand, but the namespace keeps the structure easy to follow.
Comparison with require
# require loads immediately
require 'heavy_library' # Slow startup
# autoload loads on first use
autoload :HeavyLibrary, 'heavy_library'
# Fast startup, but first use is slower
The contrast with require is what makes autoload easier to understand in context. require is immediate and predictable, while autoload trades some of that certainty for lower startup cost. That tradeoff can be worthwhile in a large application, but it is important to keep it visible in the code.
Use cases
Large applications
# Rails-like autoloading
# Only load admin code when admin is used
autoload :AdminController, 'controllers/admin_controller'
# Only load reporting when needed
autoload :ReportGenerator, 'services/report_generator'
Large applications are the most obvious place for this feature because not every subsystem needs to load right away. When the codebase grows, delaying a few expensive files can make the initial boot path easier to manage. It also keeps the main entry point from doing work that the current request may never need.
Plugin systems
module MyApp
# Register plugins lazily
autoload :MarkdownPlugin, 'plugins/markdown'
autoload :SyntaxPlugin, 'plugins/syntax'
end
Plugin systems benefit from lazy loading because the available features may change over time. A plugin constant can stay dormant until the feature is requested, which keeps optional code from weighing down the baseline path. That is especially helpful when the app loads many add-ons but only uses a few in each run.
Important notes
# autoload only works with constants (capitalized)
autoload :MyClass, 'my_class'
autoload :MY_CONSTANT, 'constants/my_constant'
# Won't work with lowercase
# autoload :variable, 'file' # Error!
# Can check if constant is defined
defined?(User) # => nil if not loaded, "constant" if loaded
These rules are worth spelling out because autoload only works when the constant names are predictable. Lowercase names are treated as variables, not constants, so the loader has nothing to hook into. The defined? check is a small but practical tool when you want to see whether the file has already been loaded.
With namespaces
# Module handles the namespace
module Admin
autoload :User, 'admin/user'
end
# Access as
Admin::User
Namespaces keep the constant lookup explicit and make the lazy-loading behavior easier to reason about. If a module owns a set of related constants, the loader can attach them in one place while the rest of the code still uses the familiar qualified name. That usually reads better than spreading the same pattern across unrelated files.
Modern alternatives
In Ruby 3+, consider using Zeitwerk for automatic gem loading, but autoload remains useful for custom lazy loading strategies.
Practical guidance
autoload works best in codebases where constant loading is predictable and the team agrees on the file layout. It can keep boot time low, but it also makes load order matter more, so it is usually a better fit for larger codebases than for tiny scripts.
If you use it, keep the constant name and file path aligned with project conventions. That makes the first reference to a constant much easier to trace when you are reading or debugging the code.