Open-Source Wikis

/

Ruby on Rails

/

Features

/

Generators and the CLI

rails/rails

Generators and the CLI

How bin/rails works, the Thor-based command system, and the generator framework that powers rails new and rails generate.

The CLI entry point

railties/exe/rails is a one-line bootstrap:

require "rails/cli"

railties/lib/rails/cli.rb figures out where it's being invoked from:

  • Inside a Rails app — load config/boot.rb and dispatch to Rails::Command.
  • Outside an app — fall back to Rails::AppLoader to either find an app in a parent directory or run the meta-command (rails new).

Rails::Command (railties/lib/rails/command.rb) is the dispatcher. It uses Thor's command lookup, with an extra layer that finds commands across:

  • The rails/commands/<name>/<name>_command.rb directories.
  • Engine-shipped commands.
  • App-defined commands under lib/tasks/.

Built-in commands

railties/lib/rails/commands/:

  • about — versions, env, database (in about_command.rb).
  • app — manage the app's structure.
  • boot — boot the app and exit (useful for measuring boot time).
  • console — IRB with the app loaded.
  • credentials / encrypted / secret — encrypted credentials.
  • dbdb:create, db:migrate, db:rollback, db:seed, db:reset, etc.
  • dbconsole — open the database client.
  • dev — toggle dev caching, profile dev mode.
  • devcontainer — generate / update .devcontainer/.
  • destroy — undo a generator.
  • gem_help, help — built-in help.
  • generate — invoke a generator.
  • initializers — print the resolved initializer order.
  • middleware — print the middleware stack.
  • newrails new myapp.
  • notes — collect annotations (TODO, FIXME, etc.) from source.
  • pluginrails plugin new.
  • query — read-only query console (new in 8.2).
  • restart — touch tmp/restart.txt.
  • routes / unused_routes — show or audit the route table.
  • runner — run a Ruby script with the app loaded.
  • secret — generate a random secret.
  • server — boot the web server.
  • stats — code statistics for the app.
  • test / test:system — Minitest runner.

Each command lives in its own directory (commands/<name>/<name>_command.rb) and is a Thor subclass.

Command resolution

graph LR
    A["bin/rails X"] --> B[Rails::CommandsTasks]
    B --> C{X is a command?}
    C -->|yes| D[Rails::Command.invoke]
    C -->|no| E[fall through to Rake]
    D --> F[Thor: parse args, run command]
    E --> G["Rake task X"]

If a name isn't a registered command, the dispatcher falls through to Rake. This is why bin/rails routes is a command but bin/rails db:migrate is a Rake task (technically — the db:migrate command is a thin wrapper around the Rake task).

Generator framework

railties/lib/rails/generators/:

  • base.rbRails::Generators::Base, a Thor::Group subclass.
  • app_base.rb — shared bits between rails new and rails plugin new.
  • named_base.rb — for resource-named generators (scaffold, model, controller).
  • actions.rb — high-level helpers (gem, route, environment, git, template).
  • database.rb — picks the right database adapter scaffolding.
  • js_package_manager.rb — Yarn/npm/bun/Importmap selection.
  • migration.rb, model_helpers.rb, resource_helpers.rb — shared scaffolding.
  • rails/ — the built-in generators.
  • test_unit/ — generators for test files (one per resource type).
  • erb/ — view scaffolding templates.

Built-in generators

railties/lib/rails/generators/rails/:

  • app/rails new (the largest generator; ~50 files).
  • application_record/
  • assets/
  • benchmark/
  • channel/
  • controller/
  • db/system/change/
  • devcontainer/
  • dev_container/
  • generator/
  • helper/
  • integration_test/
  • master_key/ / credentials/
  • migration/
  • model/
  • plugin/
  • resource/
  • scaffold/
  • scaffold_controller/
  • script/
  • system_test/
  • task/

Each generator is a Thor::Group of named tasks. For example, Rails::Generators::ScaffoldGenerator invokes model, scaffold_controller, helper, assets, system_test, and test_unit:scaffold in sequence.

Application generator

Rails::Generators::AppGenerator (railties/lib/rails/generators/rails/app/app_generator.rb) is the most complex. It creates:

  • Gemfile, Gemfile.lock (skeleton)
  • config/ (application.rb, environments, initializers, routes, database.yml)
  • app/ (controllers, models, views, helpers, channels, jobs, mailers)
  • bin/ (rails, setup, dev, ci, kamal-style scripts)
  • db/seeds.rb
  • test/ (or spec/ if --rspec)
  • Dockerfile, .dockerignore, bin/docker-entrypoint
  • .kamal/secrets, config/deploy.yml (Kamal scaffolding)
  • config/storage.yml (Active Storage)
  • config/cable.yml (Action Cable)
  • app/javascript/ (if Importmap is the default)
  • package.json if a JS bundler is selected

Many decisions are flag-driven: --api, --minimal, --javascript=esbuild, --css=tailwind, --database=postgresql, etc. Each option is implemented as a method group inside AppGenerator plus lib/rails/generators/rails/app/templates/.

Testing generators

Rails::Generators::TestCase (railties/lib/rails/generators/test_case.rb) is a base class that provides:

  • run_generator — invoke the generator in a temp directory.
  • assert_file, assert_no_file, assert_directory.
  • File content assertions via regexes.

Tests live under railties/test/generators/.

Application templates

The --template flag and the standalone bin/rails app:template command apply a template script to an existing app:

rails new myapp --template=https://example.com/template.rb

The DSL exposed by templates is in railties/lib/rails/generators/actions.rb: gem, gem_group, add_source, route, inside, git, generate, rake, rails_command, environment, lib, vendor, initializer, template, after_bundle.

Configuration

config.generators (set in config/application.rb) controls generator defaults:

config.generators do |g|
  g.test_framework :minitest
  g.fixture_replacement :factory_bot
  g.javascript_engine :esbuild
end

Implementation in railties/lib/rails/generators.rb. Apps can also override defaults per-environment.

Hooks and discovery

Rails::Generators.hide_namespace hides built-in generators from the help output. Rails::Generators.invoke is the public entry point used by rails generate <name>.

Generators discovered:

  1. Across all loaded gems, scanning lib/generators/<name>/<name>_generator.rb.
  2. From the app at lib/generators/<name>/<name>_generator.rb.
  3. From engines via their Rails::Engine.generators block.

Entry points for modification

  • Adding a sub-command: new Rails::Command::Base subclass under railties/lib/rails/commands/<name>/<name>_command.rb. Tests under railties/test/commands/.
  • Adding a generator: new Rails::Generators::NamedBase subclass under railties/lib/rails/generators/rails/<name>/. Templates under the same directory's templates/. Tests under railties/test/generators/.
  • Modifying rails new: edit Rails::Generators::AppGenerator and templates under railties/lib/rails/generators/rails/app/templates/. There's a lot of test coverage here — rake test:isolated exercises real generator runs.

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

Generators and the CLI – Ruby on Rails wiki | Factory