Gems & Bundler
Reviewed & published by Brayan K
Ruby is a dynamic, beginner-friendly programming language with a famous ecosystem of gems — packaged libraries you can install and require — managed reliably with Bundler.
Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
By the end of this lesson you'll install and require gems, write a Gemfile, and understand how Bundler locks versions for reproducible projects.
What You'll Learn in This Lesson
- What a gem is and where gems come from
- Installing gems with gem install
- Loading code with require
- Writing a Gemfile
- How Bundler locks versions (Gemfile.lock)
- Version constraints like ~>
1️⃣ Installing and Using Gems
Install a gem from your terminal with gem install name, then load it in code with require. Ruby's standard library already includes many useful libraries — like json — that you can require without installing anything.
# A gem is a packaged Ruby library. Install one from your terminal:
# gem install httparty
#
# Then require it in your code and use it:
require "json" # 'json' ships with Ruby (standard library)
data = { name: "Ada", langs: ["Ruby", "Python"] }
# Turn a Ruby hash into a JSON string:
json_string = data.to_json
puts json_string # -> {"name":"Ada","langs":["Ruby","Python"]}
# Parse a JSON string back into a Ruby hash:
parsed = JSON.parse('{"city":"London","year":2026}')
puts parsed["city"] # -> London
puts parsed["year"] # -> 2026
# Pretty-print it:
puts JSON.pretty_generate(data)2️⃣ Bundler: A Gemfile for Reproducible Projects
Real projects declare their gems in a Gemfile. Running bundle install resolves versions and writes a Gemfile.lock, so everyone installs the same versions. Run your app with bundle exec to use exactly those gems.
# Bundler manages a project's gems so everyone gets the SAME versions.
#
# 1) Create a Gemfile (a file literally named "Gemfile") in your project:
#
# source "https://rubygems.org"
# gem "httparty", "~> 0.21"
# gem "rspec", group: :test
#
# 2) Install everything listed, locking exact versions to Gemfile.lock:
# bundle install
#
# 3) Run your app through Bundler so it uses those exact gems:
# bundle exec ruby app.rb
#
# In code, you then require what you declared:
require "json" # (stand-in for a third-party gem here)
puts "Gems loaded via Bundler!" # -> Gems loaded via Bundler!
# Check installed gems from the terminal:
# gem list
# bundle listYour turn. Use the json gem to serialise and parse settings. Confirm the two TODO lines, then run it.
# 🎯 YOUR TURN — replace each TODO, then run with: ruby config.rb
require "json" # 👉 TODO: require the standard-library json gem
# 1) Build a small settings hash
settings = {
app: "MyTool",
version: "1.0",
features: ["login", "export"]
}
# 2) Convert it to a JSON string and print it
puts settings.to_json # 👉 TODO: call to_json on the hash
# 3) Parse a JSON string and read a value
incoming = '{"theme":"dark","fontSize":14}'
config = JSON.parse(incoming)
puts "Theme: #{config["theme"]}"
# ✅ Expected output:
# {"app":"MyTool","version":"1.0","features":["login","export"]}
# Theme: darkMini-Challenge: Write a Gemfile
Author a real Gemfile with a source, a pinned gem, and a test-group gem — then note the commands you'd run. This is the file at the heart of every Ruby project.
# 🎯 MINI-CHALLENGE: write a Gemfile (no code to run).
# Save it as a file literally named "Gemfile".
#
# 1. Add the rubygems source line.
# 2. Add the "httparty" gem with a pessimistic version "~> 0.21".
# 3. Add "rspec" but only in the :test group.
# Then describe (in a comment) the two commands you'd run.
#
# ✅ Example Gemfile contents:
# source "https://rubygems.org"
# gem "httparty", "~> 0.21"
# group :test do
# gem "rspec"
# end
# # Run: bundle install then bundle exec ruby app.rb
# your Gemfile hereCommon Errors (and the fix)
- "cannot load such file -- xyz" (LoadError) — The gem isn't installed or isn't required. Run gem install xyz and add require "xyz".
- Version conflicts — Two gems need incompatible versions. Let Bundler resolve them via bundle install and read its message.
- Forgetting bundle exec — Running ruby app.rb may pick a wrong global gem; use bundle exec.
- Not committing Gemfile.lock — Without it, teammates get different versions. Commit it for applications.
- Permission errors on install — Avoid sudo; use a version manager (rbenv/RVM) so gems install in your user space.
Pro Tips
- 💡 Browse gems: search rubygems.org and check downloads and last-updated dates before depending on a gem.
- 💡 Pin with ~>: it permits safe updates while blocking breaking major versions.
- 💡 Groups matter: put dev/test gems in groups so production stays lean.
📋 Quick Reference — Gems & Bundler
| Concept | Ruby Syntax |
|---|---|
| Install a gem | gem install httparty |
| Load in code | require "httparty" |
| Declare | gem "rspec", "~> 3.0" |
| Install set | bundle install |
| Run via Bundler | bundle exec ruby app.rb |
| List gems | gem list |
🎉 Lesson Complete!
- ✅ A gem is a packaged Ruby library from RubyGems.org
- ✅ Install with gem install, load with require
- ✅ A Gemfile declares a project's gems
- ✅ bundle install locks versions in Gemfile.lock
- ✅ ~> allows safe upgrades while blocking breaking ones
Practice quiz
What is a gem?
- A Ruby keyword
- A packaged, shareable Ruby library
- A type of variable
- A built-in data structure
Answer: A packaged, shareable Ruby library. A gem is a packaged Ruby library with code plus metadata, published to RubyGems.org.
Which command installs a gem globally from the terminal?
- bundle install
- gem install name
- require name
- gem load name
Answer: gem install name. gem install name fetches and installs a single gem globally on your system.
How do you load an installed gem in your code?
- import gem
- include gem
- require "name"
- load gem
Answer: require "name". You load a gem (or standard-library module) in code with require "name".
What file declares a project's gems for Bundler?
- Gemfile
- package.json
- gems.txt
- Rakefile
Answer: Gemfile. A file literally named Gemfile lists the gems a project needs.
What does `bundle install` write to lock exact versions?
- Gemfile
- Gemfile.lock
- versions.rb
- lockfile.json
Answer: Gemfile.lock. bundle install resolves versions and records the exact ones in Gemfile.lock.
What does the `~>` version constraint mean?
- Exactly this version
- Any version
- Pessimistic: safe minor/patch upgrades, no breaking major bump
- Less than this version
Answer: Pessimistic: safe minor/patch upgrades, no breaking major bump. ~> is the pessimistic operator; ~> 0.21 means at least 0.21 but less than 1.0.
Why run your app with `bundle exec`?
- It is faster
- It ensures the exact gems from the Gemfile/lock are used, not some global version
- It installs gems
- It compiles the app
Answer: It ensures the exact gems from the Gemfile/lock are used, not some global version. bundle exec runs your app with exactly the gems Bundler resolved, avoiding wrong global versions.
Which library ships with Ruby and needs no install before `require`?
- httparty
- rails
- json
- rspec
Answer: json. json is part of Ruby's standard library, so you can require it without installing anything.
What error appears when a required gem isn't installed?
- SyntaxError
- LoadError (cannot load such file)
- ArgumentError
- NameError
Answer: LoadError (cannot load such file). Requiring a missing gem raises LoadError: 'cannot load such file'.
What is the difference between gem install and bundle install?
- No difference
- gem install adds one gem globally; bundle install installs the whole Gemfile set with locked versions
- gem install needs a Gemfile
- bundle install installs only one gem
Answer: gem install adds one gem globally; bundle install installs the whole Gemfile set with locked versions. gem install is for single global tools; bundle install installs a project's whole declared, version-locked set.
Continue this course
- Previous: Metaprogramming Intro
- Next: String Methods — Interpolation, gsub/sub, split/join, format, and the bang methods
- Quick reference: Ruby cheat sheet
Frequently asked questions
What exactly is a gem?
A gem is a packaged, shareable Ruby library — a bundle of code, plus metadata like its name, version, and dependencies. Gems are published to RubyGems.org, the central repository, and you install them with the gem command (gem install rails). Once installed, you load a gem in your code with require. There are gems for almost everything: web frameworks (Rails, Sinatra), HTTP clients (HTTParty), testing (RSpec), and tens of thousands more. The standard library also ships many ready-to-require modules like json and csv.
What problem does Bundler solve?
Bundler manages the set of gems a project needs and, crucially, their exact versions. You list your gems in a Gemfile, run bundle install, and Bundler resolves compatible versions and records the exact ones in a Gemfile.lock. Committing that lock file means every developer — and your production server — installs identical versions, eliminating 'works on my machine' bugs caused by version drift. Running your app with bundle exec ensures it uses exactly those gems and not some other version installed globally.
What does the version constraint ~> mean?
~> is the 'pessimistic' or 'twiddle-wakka' operator, and it allows safe upgrades within a range. gem "httparty", "~> 0.21" means 'at least 0.21, but less than 1.0' — it lets in compatible patch and minor updates while blocking a major version that might break things. A more specific ~> 0.21.3 means 'at least 0.21.3 but less than 0.22'. It's the most common constraint because it balances getting bug fixes with avoiding surprises from breaking changes.
What's the difference between gem install and bundle install?
gem install fetches a single gem and installs it globally on your system, which is fine for command-line tools you want everywhere (like rails or bundler itself). bundle install reads your project's Gemfile and installs the whole declared set, recording exact versions in Gemfile.lock for reproducibility. For application development you almost always use Bundler so the project's dependencies are explicit, versioned, and shared. Think of gem install for global tools and bundle install for project dependencies.