Open-Source Wikis

/

Ruby on Rails

/

Features

/

Autoloading

rails/rails

Autoloading

Rails uses Zeitwerk for autoloading and code reloading. This page documents the integration: which loaders exist, how the autoload paths are configured, and how reloading works in development.

Two loaders

Rails::Autoloaders (railties/lib/rails/autoloaders.rb) configures two Zeitwerk loaders per application:

  • main — for code that participates in development reloading. Drives app/, the lib/ paths the app added, and engine app/ paths.
  • once — for code that loads at boot and is not reloaded. Used for engine internals and anything declared via config.autoload_once_paths.
# railties/lib/rails/autoloaders.rb
class Rails::Autoloaders
  def initialize
    @main = Zeitwerk::Loader.new
    @once = Zeitwerk::Loader.new
    @main.tag = "rails.main"
    @once.tag = "rails.once"
  end
end

Both loaders share a single inflector configured from Rails.autoloaders.main.inflector.

Autoload paths

Three configurable arrays in Rails::Engine::Configuration:

  • autoload_paths — directories Zeitwerk will scan, reloaded in dev. Defaults to app/* (app/models, app/controllers, etc.) and app/*/concerns.
  • autoload_once_paths — directories that must be loaded once and never reloaded.
  • eager_load_paths — directories that get fully required when config.eager_load = true (production by default).

add_lib_to_load_path! (in application.rb) prepends lib/ to $LOAD_PATH even if lib/ isn't in any autoload list. By default in 7.x+, Rails does not add lib/ to autoload paths automatically — apps opt in via config.autoload_lib(ignore: %w[assets tasks]).

Boot integration

The autoloaders are set up by initializers in railties/lib/rails/application/bootstrap.rb and the engine's own initializers:

graph TD
    A[Engine#initialize_eager_load] --> B[Compute eager_load_paths]
    B --> C[Add to Zeitwerk loaders]
    C --> D[Eager load if production / config.eager_load]
    D --> E[App ready]

For each engine's autoload paths, Rails.autoloaders.main (or once) calls loader.push_dir(path). Then loader.setup finalizes registration with Zeitwerk's underlying tracepoint.

Reloading in development

When config.enable_reloading = true (the dev default), ActiveSupport::Reloader watches files via ActiveSupport::EventedFileUpdateChecker (or FileUpdateChecker as a fallback). On every request:

sequenceDiagram
    participant MW as ActionDispatch::Reloader
    participant Reloader as ActiveSupport::Reloader
    participant Files as FileUpdateChecker
    participant Z as Zeitwerk
    MW->>Reloader: prepare!
    Reloader->>Files: any updated?
    alt files changed
        Files-->>Reloader: yes
        Reloader->>Z: reload!
        Z->>Z: unload all autoloaded constants
        Z->>Reloader: ready for next load
    else no change
        Files-->>Reloader: no
    end
    Reloader-->>MW: ready

Zeitwerk::Loader#reload is what actually unloads the autoloaded constants. The to_prepare callbacks run after every reload to re-initialize state that depends on autoloaded classes.

Conventions Zeitwerk requires

Zeitwerk is strict about the file-name to constant-name mapping:

  • app/models/user.rbUser
  • app/models/admin/user.rbAdmin::User
  • app/controllers/api/v1/posts_controller.rbApi::V1::PostsController

Acronyms work via the inflector:

Rails.autoloaders.main.inflector.inflect("api" => "API", "v1" => "V1")

config/initializers/inflections.rb is the standard place to add these.

eager_load

In production, config.eager_load = true triggers a recursive require of every constant in the eager_load_paths during boot. Implementation in railties/lib/rails/application/finisher.rb (:eager_load! initializer). Eager loading:

  • Surfaces autoload errors at boot rather than at first request.
  • Allows the framework to fork without copy-on-write penalties.
  • Lets Bootsnap (bootsnap-precompile) cache compiled bytecode.

bin/rails zeitwerk:check (in an app) verifies that every file in autoload paths can be loaded without errors and that constant names match file paths.

Eager load namespaces

A railtie or engine can mark parts of itself as eager loadable:

# railties/lib/rails/railtie.rb provides this
config.eager_load_namespaces << MyEngine

Then Rails.application.eager_load! walks each namespace's autoload paths.

Custom loaders

Engines that need their own loader (e.g., to scan a non-standard layout) can declare:

class MyEngine::Engine < Rails::Engine
  initializer "my_engine.add_loader" do |app|
    Rails.autoloaders.once.push_dir("#{root}/lib/my_engine")
  end
end

Rails.autoloaders.once is for engine internals — code that should be loaded once and not reloaded with the app.

Autoload helpers in components

Components use Active Support's autoload helpers (activesupport/lib/active_support/dependencies/autoload.rb) to declare lazy module loading at the framework level:

module ActiveRecord
  extend ActiveSupport::Autoload
  autoload :Base
  autoload :Relation
  autoload :Migration
end

These are not tied to Zeitwerk — they're a thin wrapper around Ruby's autoload keyword that expands relative paths against the calling file's directory.

Common pitfalls

  • Constant naming mismatches. Zeitwerk insists on the file name matching the constant. Add inflections for acronyms.
  • Modifying $LOAD_PATH outside autoload. Don't require files inside autoload paths; let Zeitwerk handle it.
  • Holding references across requests. A reloaded class is a new constant; old references point at stale classes.
  • lib/ is not autoloaded by default in modern Rails. Use config.autoload_lib(ignore: %w[assets tasks]) to opt in.

Entry points for modification

  • The autoloader entry point is railties/lib/rails/autoloaders.rb.
  • File-watching strategies are activesupport/lib/active_support/file_update_checker.rb and evented_file_update_checker.rb.
  • The reloader is activesupport/lib/active_support/reloader.rb and the executor is activesupport/lib/active_support/execution_wrapper.rb.
  • The middleware that wraps requests in the reloader is actionpack/lib/action_dispatch/middleware/reloader.rb.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Autoloading – Ruby on Rails wiki | Factory