Ruby Rake
last modified October 18, 2026
Rake is a build automation tool for Ruby, often described as "make" written in
Ruby. Tasks are written in plain Ruby inside a file called Rakefile,
and the rake command runs them. Rake handles task dependencies,
file-based rebuilds, namespaces, and listing of documented tasks. This guide
covers the core features of Rake with runnable examples.
Rakefile and Simple Tasks
A Rakefile lives in the project root. Each task is declared with
task :name do ... end, and running rake name executes
its block. The desc method attaches a description to the next task;
rake -T lists all described tasks. Tasks without a desc
are still runnable but are hidden from the list.
desc "Say hello"
task :hello do
puts "Hello from Rake!"
end
desc "Print the current Ruby version"
task :version do
puts "Ruby #{RUBY_VERSION}"
end
Each task is a named block of Ruby code. The desc lines provide the
descriptions shown by rake -T, which prints the task names together
with their descriptions.
$ rake hello Hello from Rake! $ rake version Ruby 3.0.2 $ rake -T rake hello # Say hello rake version # Print the current Ruby version
Task Dependencies
Tasks can depend on other tasks. The syntax task build: [:compile]
declares that build must run after compile. Rake runs
each prerequisite once per invocation, in the order they are declared, before
running the task itself. Multiple prerequisites are given as an array.
task :compile do puts "Compiling sources..." end task :test do puts "Running tests..." end task build: [:compile] do puts "Build complete" end task release: [:build, :test] do puts "Release ready" end
Running release first resolves its prerequisites: build
requires compile, and test is also required. Rake
executes them in dependency order, so the output shows compilation before the
build finishes and tests before the release step.
$ rake release Compiling sources... Build complete Running tests... Release ready
Tasks with Arguments
Task arguments are declared as a list of symbols after the task name:
task :greet, [:name, :greeting] do |t, args|. Values are passed on
the command line in square brackets, separated by commas. The
with_defaults method supplies fallback values for arguments that were
not provided. Quote the whole argument when using a shell such as bash, because
brackets are special there.
desc "Greet a user"
task :greet, [:name, :greeting] do |t, args|
args.with_defaults(greeting: "Hello")
puts "#{args.greeting}, #{args.name}!"
end
The block receives the task object t and an args
object. Each declared argument is accessible as a method on args.
Without with_defaults, a missing argument would be nil.
$ rake "greet[Alice]" Hello, Alice! $ rake "greet[Bob,Hi]" Hi, Bob!
File Tasks
A file task, declared with file "out" => ["in"] do ... end,
produces a file from its prerequisites. Rake runs the block only when the target
file does not exist or is older than one of its prerequisites. This makes
repeated runs incremental: if nothing has changed, the task does nothing.
file "hello.o" => ["hello.c"] do |t|
puts "cc -c #{t.prerequisites.first} -o #{t.name}"
File.write(t.name, "object code\n")
end
Inside the block, t.name is the target file and
t.prerequisites lists its inputs. The example writes a placeholder
object file so the second run can detect that it is up to date. When
hello.o already exists and is newer than hello.c, the
second invocation prints nothing.
$ printf 'int main(void) { return 0; }\n' > hello.c
$ rake hello.o
cc -c hello.c -o hello.o
$ rake hello.o
Namespaces and the Default Task
The namespace block groups related tasks under a prefix, so
task :migrate inside namespace :db is invoked as
rake db:migrate. A task named default runs when
rake is called without arguments. Prerequisites may refer to
namespaced tasks by their full name, such as "db:migrate".
namespace :db do
desc "Migrate the database"
task :migrate do
puts "Running migrations"
end
desc "Seed the database"
task :seed => :migrate do
puts "Seeding data"
end
end
task default: "db:seed"
Because db:seed depends on db:migrate, running the
default task executes the migration first and then the seed step. Inside the
namespace, the short name :migrate resolves to db:migrate.
$ rake Running migrations Seeding data $ rake -T rake db:migrate # Migrate the database rake db:seed # Seed the database
Rake::FileList
Rake::FileList is a collection of file paths built from glob
patterns. It behaves like an array of strings but supports exclusion patterns and
path manipulation methods such as ext for changing extensions. It
is commonly used to build the lists of sources and objects for file tasks.
files = Rake::FileList["*.txt"] desc "List text files" task :list do puts files.to_a.inspect end
The glob *.txt is expanded when the Rakefile is loaded. Calling
to_a converts the list to a plain Ruby array before printing it.
The output shown assumes the directory contains a.txt and
b.txt; your list will differ if other text files are present.
$ rake list ["a.txt", "b.txt"]
Best Practices
Keep Rakefiles small by moving reusable logic into Ruby files under a
lib/ directory and requiring them from the Rakefile. Always add a
desc to tasks you want others to use, so they appear in
rake -T. Prefer file tasks over plain tasks when output is a file,
since Rake then skips work that is already up to date. Use namespaces to avoid
name collisions in larger projects.
List all Ruby tutorials.
Author
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.