Kernel#exit
exit(status = 0) -> never returns The exit method terminates the Ruby program immediately. It raises a SystemExit exception which, by default, is not caught, causing the program to terminate. That makes it a blunt but clear way to stop a script once it has finished its work.
The examples below move from the simplest exit to an explicit status code and then to a rescue case. That sequence shows both sides of the method: how it ends a process and how surrounding code can intercept that ending when needed.
Syntax
exit
exit(status)
exit(status: code)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
status | Integer | 0 | The exit status code returned to the operating system. A status of 0 indicates success; non-zero indicates failure. |
The status integer is the only argument, and it defaults to zero when omitted. That default keeps the simplest case clean.
Examples
Basic usage
puts "Starting program..."
exit
puts "This will never run"
# Output: Starting program...
A bare exit call with no argument is the simplest form. It stops execution immediately and returns a success code of 0 to the shell. Everything after the call is skipped, which is why the second puts never runs. This makes exit especially straightforward in simple scripts.
Exiting with a status code
begin
file = File.open("data.txt")
rescue Errno::ENOENT
puts "Error: File not found"
exit(1) # Exit with error status
end
# If we reach here, exit with success
exit(0)
The explicit status code matters because it becomes part of the contract with the shell. A zero code reads as success, while a non-zero code tells the caller that something went wrong and should be handled differently. Choosing the right status code keeps scripts predictable when they are chained together in pipelines.
Using keyword argument
exit(status: 42)
The keyword form makes the intent even clearer in code that already uses named arguments. It reads like a direct statement of purpose instead of a shorthand the reader has to decode. The keyword form is also easier to change later if the status value becomes a constant or a computed result rather than a hard-coded integer.
Common Patterns
Using exit in CLI tools
require 'optparse'
options = {}
OptionParser.new do |opts|
opts.on("-v", "--version", "Show version") do
puts "MyApp version 1.0"
exit(0)
end
end.parse!
In a small CLI, this pattern keeps the success path and the exit path close together. The user gets an immediate response, and the command ends with a status that the shell can reuse. This is a clean way to handle the --version and --help flags in command-line tools because the user gets what they asked for and the program stops without running any further logic.
Preventing accidental exit
begin
exit(1)
rescue SystemExit => e
puts "Exit attempted with status: #{e.status}"
# Handle gracefully instead of terminating
end
Rescuing SystemExit is unusual, but it can be useful in tests or wrapper code that needs to observe the exit attempt without actually ending the process. The key is to treat it as a deliberate exception-handling choice, not a default habit. In most applications, though, letting the process end is the right call. Rescuing SystemExit should be reserved for testing frameworks, wrappers, and other code that needs to observe the exit without actually terminating.
Errors
Calling exit raises a SystemExit exception. If this exception is not caught, the program terminates with the specified status. To prevent termination, you can rescue SystemExit:
begin
exit(1)
rescue SystemExit
puts "Caught exit attempt"
end
puts "Program continues"
# Output: Caught exit attempt
# Output: Program continues
That example shows the exception path clearly: exit still raises, but rescue can intercept it if the surrounding code really needs to keep going. In normal scripts, though, the simpler choice is usually to let the process end and trust the status code.
Exiting deliberately
exit is best used when the program has reached a point where continuing would be misleading or unsafe. That is common in command-line tools after a fatal error or after a successful one-shot task is complete. Because the method raises SystemExit, the surrounding code should be careful about where it is called and what cleanup needs to happen first. A short, obvious exit path is usually easier to maintain than scattering process termination across several branches.
If you need to keep the process alive after an error, rescuing SystemExit is an explicit choice that should be made only in code that understands the consequences. Otherwise, let the program end normally and keep the exit status meaningful for the caller or shell.
Choosing a status that tells the truth
The exit status is part of the contract with the shell or the calling process, so it should reflect what really happened. A successful run should return a success code, while a failed validation or missing dependency should signal that something went wrong. That small detail makes scripts easier to chain together and makes automation more reliable. When the code exits on purpose, a clear message before the exit often saves the next person a lot of guessing.
When you are writing a script, the safest habit is to decide the status code where the failure is detected and then exit once at the boundary. That keeps the flow simple and makes the process ending easy to reason about from the outside.