skip to content

In Ruby 4.0's IRB, which rc files run at startup, in what order, and why is an .irbrc inside a cloned repository a risk?

level: seniorimportance: should knowfreq 22%

answer

  1. IRBRC env var wins first
  2. XDG_CONFIG_HOME/irb/irbrc, ~/.irbrc
  3. then ./.irbrc in the current directory
  4. every file found is loaded
  5. irb -f skips them all

basics

~20 s

IRB loads every rc file it finds: the IRBRC path, the XDG config file, ~/.irbrc or ~/.config/irb/irbrc, then .irbrc in the current directory. Each is plain Ruby, so a repository's .irbrc runs arbitrary code; irb -f skips them.

solid answer

~40 s

An rc file is Ruby that IRB `load`s before the first prompt, usually to set `IRB.conf` keys such as `:SAVE_HISTORY`, `:EVAL_HISTORY`, `:PROMPT_MODE` or `:COMMAND_ALIASES`. The IRB that Ruby 4.0 bundles builds a list in order: the file named by `IRBRC`, `$XDG_CONFIG_HOME/irb/irbrc`, `~/.irbrc`, `~/.config/irb/irbrc` when `XDG_CONFIG_HOME` is unset, then `.irbrc`, `irbrc`, `_irbrc` or `$irbrc` in the **current directory** — and loads **every** one that exists. A failing file only prints a warning. Because it is ordinary Ruby, running `irb` inside a freshly cloned repository executes that repository's `.irbrc` with your permissions. `irb -f` disables rc loading entirely; reading an unfamiliar project's `.irbrc` first is the safer habit.

code

ruby · 10 lines
ruby
# ~/.irbrc
IRB.conf[:SAVE_HISTORY] = 5000
IRB.conf[:EVAL_HISTORY] = 20
IRB.conf[:COMMAND_ALIASES] = {"$": :show_source, "@": :whereami, s: :show_source}

begin
  require "csv"
rescue LoadError
  warn "csv not in this bundle"
end

go deeper

for a junior

Know that ~/.irbrc is Ruby that runs when IRB starts and is where settings like history size go.

for a middle

List the lookup order, including IRBRC, XDG paths and the current directory, and explain that every existing file is loaded.

for a senior

Treat a repository's .irbrc as executable code: read it before running IRB in untrusted checkouts, and know irb -f to bypass it.

for a principal

Decide whether a team ships a shared project .irbrc at all, weighing onboarding convenience against running unreviewed code on every developer's machine.

## What an rc file is When IRB starts it runs one or more **rc files** ("run commands") before printing its first prompt. They are not a config format: each one is loaded with Ruby's `load`, so it can contain any Ruby code at all. Typical contents set keys in the `IRB.conf` hash: - `IRB.conf[:SAVE_HISTORY] = 5000` — input lines kept in `.irb_history` (default 1000); - `IRB.conf[:EVAL_HISTORY] = 20` — enables `__`, the history of results; - `IRB.conf[:PROMPT_MODE] = :SIMPLE` — the `>>` prompt; - `IRB.conf[:COMMAND_ALIASES]` — the command shortcuts, `$` and `@` by default; - `IRB.conf[:COMPLETOR] = :type` — the completion engine. People also define helper methods or `require` debugging libraries there. ## Where IRB looks, in order The IRB shipped with Ruby 4.0 collects candidate paths in this order and keeps those that exist: 1. the path in the **`IRBRC`** environment variable; 2. **`$XDG_CONFIG_HOME/irb/irbrc`**, if that `irb` directory exists; 3. **`~/.irbrc`**; 4. **`~/.config/irb/irbrc`**, only when `XDG_CONFIG_HOME` is unset or empty; 5. in the **current directory**: `.irbrc`, `irbrc`, `_irbrc`, `$irbrc`. Then it `load`s **each** of them in that order. That is the part older answers get wrong: earlier IRB releases stopped at the first file found, so a personal `~/.irbrc` used to hide a project one. Now a user file and a project file both run, the project's last, so its settings win where they overlap. ## Failure and escape hatches | Situation | Behaviour | |---|---| | An rc file raises `StandardError` or a `ScriptError` such as `SyntaxError` | IRB prints `Error loading RC file` with the message and carries on. | | A known `IRB.conf` key has a wrong type (e.g. `EVAL_HISTORY` not an Integer) | Startup fails IRB's config validation with a `TypeError`. | | You start `irb -f` | No rc file is loaded at all. | The same rc files are read when IRB is started for you — `binding.irb`, IRB-based framework consoles — because they all go through IRB's setup. ## Why a project .irbrc is a risk Loading the current directory's `.irbrc` is convenient for teams (shared helpers, a project prompt), but it means **opening a console runs code chosen by whoever wrote that file**: - clone an unfamiliar repository, `cd` into it, type `irb`, and its `.irbrc` executes with your user's permissions — reading `~/.ssh`, environment variables and tokens included; - nothing prompts or warns first; the file is just `load`ed; - because the file is Ruby, reviewing it is the only way to know what it does. Practical defences: - read `.irbrc` (and `irbrc`, `_irbrc`) before starting IRB in code you did not write; - use `irb -f` when you only need a clean console; - keep secrets out of shell environments used for exploring untrusted code. ## Keeping your own rc file healthy - Guard optional libraries: `begin; require "amazing_print"; rescue LoadError; end` so a missing gem under Bundler only skips a feature. - Keep it fast; it runs on every console start. - Use `IRBRC` to point CI or containers at a known file, or `-f` to run with none.

  • You have both ~/.irbrc and a project .irbrc that set IRB.conf[:PROMPT_MODE] differently. Which wins?
    The project file. Current IRB loads every rc file it finds, user-level locations first and the current directory's `.irbrc` last, so the later assignment to `IRB.conf[:PROMPT_MODE]` overwrites the earlier one. Older IRB releases loaded only the first file found and would have used `~/.irbrc` alone.
  • Your ~/.irbrc raises NameError on a typo. Does IRB refuse to start?
    No. IRB rescues `StandardError` and `ScriptError` from each rc file, prints `Error loading RC file` with the full message, and continues to the prompt. Only IRB's own config validation — for example `IRB.conf[:EVAL_HISTORY]` set to a non-Integer — raises `TypeError` at startup.
  • How do you start IRB in an untrusted checkout without running its .irbrc?
    Run `irb -f`, which sets `IRB.conf[:RC]` to false so no rc file is loaded, including your own. Alternatively read the directory's `.irbrc`, `irbrc` and `_irbrc` first, or start IRB from another directory and `require_relative` what you need.

saying these in an interview costs you the question

  • IRB loads only ~/.irbrc and ignores any file in the current directory.
  • A project .irbrc is a data file, so opening IRB cannot execute code.
  • An exception in .irbrc stops IRB from starting at all.
  • When ~/.irbrc exists, a project .irbrc is never loaded.
  • irb --noscript is the flag that skips rc files.