Ruby:happiness
A scripting language that writes "programmer happiness" into its design goals. Shipped from Tsukuba, Japan in 1995; rode Rails into Web 2.0 dominance in 2004; reclaimed its perf credentials in 2021 via Shopify's YJIT. At 33, Ruby has never been the hottest language alive — and has never died. GitHub, Shopify, Stripe and 37signals all still run on Rails.
fj.sources, Japan
~200B downloads total
Rails workloads
on a Rails monolith
What is Ruby
Ruby is an object-oriented scripting language designed by Japanese programmer Yukihiro "Matz" Matsumoto in 1993, released publicly in 1995. Three traits shape every Ruby idiom: pure OO (everything is an object), dynamic typing, and blocks + metaprogramming. It grew quietly in Japan from 1995 to 2004; it went global only after DHH built Rails on top of it.
More radical than Java or Python: 1, nil, true, and classes themselves are all objects. There is no primitive/object split — nothing escapes the object model.
No type-check at compile time; "if it quacks, it's a duck." Sorbet / RBS provide optional side-loaded annotations, but never enter the language proper — Matz keeps saying types stay optional.
5.times { ... }, File.open(...) do |f| ... end — methods taking a block is the spine of Ruby's control flow. Where other languages need explicit closures or lambdas, Ruby gets it in one stroke.
The official implementation is MRI (Matz's Ruby Interpreter) → YARV bytecode VM (2007) → YJIT (Shopify's in-process JIT, 2021). Default-on from 3.4 — in 2026 Ruby is no longer "the slow one."
List<String> emails = new ArrayList<>();
for (User u : users) {
if (u.isActive()) {
emails.add(u.getEmail().toLowerCase());
}
}
// 7 lines · typing ceremony · null checks on youemails = users.select(&:active?)
.map(&:email)
.map(&:downcase)
# 3 lines · fluent · zero ceremony
# &:method is symbol-to-proc, signature RubyHistory : Timeline
Ruby has three clear eras: 1993–2003 the Japan-only years (Matz alone, Japanese-language community); 2004–2013 the Rails golden age (DHH carries Ruby out of Japan; Twitter / GitHub / Shopify are born on Rails); 2014–2026 the Shopify era (newer frameworks steal mindshare, but Shopify picks up the compiler — YJIT and Rails 8 give Ruby a mature second wind).
- 1993
Yukihiro "Matz" Matsumoto starts hacking
February, in Tsukuba, Japan: over lunch with a colleague Yukihiro "Matz" Matsumoto mused that there should be an object-oriented scripting language aimed at programmers. He didn't like Perl's ugliness or what he saw as Python's over-restraint, so he started writing one. The name comes from a colleague's birthstone.
- 1995·12·21
Ruby 0.95 — first public release
December 21: Matz drops Ruby 0.95 on the fj.sources Usenet group. Early development is entirely Japanese: almost no English docs, mailing lists entirely in Japanese. A language born outside the anglosphere is exceedingly rare in PL history.
- 1999·10
The first Ruby book, in Japanese
Matz and Keiju Ishitsuka publish "Object-Oriented Scripting Language Ruby." Ruby has thousands of users in Japan; abroad nobody has heard of it. The "Japan-only language" phase holds well into the early 2000s.
- 2000
"Programming Ruby" — the Pickaxe book
Dave Thomas and Andy Hunt publish the first English-language Ruby book; the pickaxe on the cover gives it the nickname. This book carries Ruby out of Japan; North American users grow from dozens to thousands over the next few years. The Pragmatic Programmer series is built on its back.
- 2003
Ruby 1.8 — the long-lived stable line
1.8 becomes the de-facto standard for the next several years. M17N (multi-byte strings) hasn't landed yet, and Unicode handling stays a sore spot in early Ruby — that wait runs to 1.9 in 2007.
- 2004·07·24
DHH releases Ruby on Rails
Danish developer David Heinemeier Hansson (DHH) extracts Ruby on Rails 0.5 from the Basecamp app he wrote inside 37signals and open-sources it on July 24. This is the inflection point for Ruby — though nobody knew it at the time.
- 2005·07
The "Blog in 15 minutes" screencast
DHH's "build a blog in 15 minutes" screencast spreads everywhere; the contrast with Java/Struts' 30-XML-file ceremony lands hard. Convention over configuration goes viral overnight; Ruby downloads double.
- 2005·12·13
Rails 1.0 ships
December 13, Rails 1.0. RJS, ActiveRecord, generators, the
acts_as_*DSL cluster — all in. For the next five years Rails is the default startup stack: Twitter, GitHub, Shopify, Airbnb, Hulu, Groupon, SoundCloud, Kickstarter — all built on Rails first. - 2007
Ruby 1.9 — the YARV bytecode VM
Koichi Sasada's YARV bytecode VM replaces 1.8's AST walker. Big speedup, plus M17N (per-string encodings) — the Unicode pain ends. But 1.9 breaks compatibility enough that the 1.8 → 1.9 migration drags on in the community for years.
- 2008·05
The Twitter scaling crisis
Twitter's Rails monolith collapses under World Cup / election-night load; the "fail whale" becomes an internet meme. The "Ruby/Rails can't scale" narrative starts here — heavily overblown later. The real cause was Ruby's GC + single-process model + early-ORM patterns being wrong for fan-out write workloads, not the language.
- 2011·04
Twitter migrates off Ruby (partially)
Twitter rewrites its search back end from Ruby/Rails to Scala on the JVM (Finagle / Storm). The front end stays Rails for years afterwards. Media compresses this into "Twitter abandoned Ruby," but it was a layered migration that took five full years.
- 2013
Ruby 2.0 — keyword args + frozen-string lead-in
2.0 ships
**kwargs, thefrozen_string_literalmagic comment and experimental refinements; perf keeps creeping up. Ruby 2.x is a decade of "steady growth" — few headlines, but constant work on GC, IO and threading. - 2014
Node / Go / Elixir steal the new-shiny crown
JavaScript on the server (Node.js), Go services, and Elixir/Phoenix start owning the "fashionable web back end" slot. Rails starts to feel "stable but dated." "Is Rails dead?" becomes an annual Hacker News thread.
- 2015
GitHub still on Rails; Shopify picks up the torch
GitHub's product is still a Rails monolith; Shopify makes Ruby/Rails core strategy and starts hiring Ruby committers en masse. Shopify takes over as Ruby's principal corporate patron — a role it still holds in 2026.
- 2018·12·25
Ruby 2.6 — MJIT lands in stdlib
The Christmas-release ritual: every December 25, Matz ships a Ruby. 2.6 merges MJIT (Vladimir Makarov's method-based JIT) into the trunk — the first time "Ruby can JIT". The speedup on pure-Ruby workloads is modest, but it lays the groundwork for the next JIT.
- 2020·12·25
Ruby 3.0 — the "3x3" goal delivered
Christmas 2020. The "Ruby 3 should be 3× faster than Ruby 2.0" target Matz set publicly in 2015 is met on benchmarks like optcarrot. Ractor (GIL-free actor concurrency) and Fiber.scheduler arrive in the same release.
- 2021·12·25
YJIT lands — Shopify steps up
Maxime Chevalier-Boisvert (formerly Université de Montréal, Basilisk JIT) joins Shopify and ships YJIT in Ruby 3.1. Basic-block versioning approach; ~2× faster on Rails workloads. It's the first time Ruby's perf gets seriously compared to V8 / PyPy in the same room.
- 2022·12·25
Ruby 3.2 — YJIT rewritten in Rust, on by default
YJIT's whole back end gets rewritten in Rust (Rust enters Ruby's mainline for the first time), and is on by default. Shopify rolls YJIT to 100% production and reports ~9% CPU savings — at their scale, tens of millions of dollars a year.
- 2023·12·25
Ruby 3.3 — YJIT faster again, Prism parser
More YJIT optimisations (lazy basic blocks, better side exits): another ~15% on Rails. Prism replaces the 25-year-old parse.y, finally giving LSPs and analysis tools a modern front end.
- 2024·11·08
Rails 8 — "No PaaS Required"
November 8, Rails World: DHH ships Rails 8. The headline is Solid Queue / Solid Cache / Solid Cable — Postgres replaces Redis / Sidekiq / Redis-backed ActionCable. The message is unmistakable: anti-fragmentation, one Postgres to start, no five-service shopping list. Kamal 2 swallows deployment too.
- 2024·12·25
Ruby 3.4 — YJIT default, Namespace experiment
YJIT is now on for everyone by default, no longer opt-in. The experimental
Namespacemodule lands on trunk — Ruby's first try at real module isolation, aimed at the monkey-patch collisions in big apps. - 2025
DHH drops TypeScript, doubles down on Hotwire
DHH says publicly, several times, that 37signals is removing TypeScript; the claim is that the errors TS catches are caught better by RuboCop and tests. Hotwire (Turbo + Stimulus + Strada) matures on Hey and Basecamp as Rails's "anti-SPA answer". All of this is loudly counter-mainstream — DHH attracts equal parts hate and devotion.
- 2026
Ruby at 33 — the niche king that won't die
State of play in 2026: GitHub is still a Rails monolith, Shopify runs a Rails app on ~$5B annual GMV-driven revenue, Stripe uses Ruby heavily, and Coinbase / Square / Instacart all started on Rails. "Rails is dead" is a 15-year-old argument and every year Ruby ships a real release. Performance has stopped being the issue; the job market is the real soft spot — younger developers reach for TS / Go / Rust first.
Language Essentials : RubyAlphabet
The eight cards below are where Ruby diverges hardest from other languages on this site: pure OO, blocks + yield, symbols, method_missing, monkey patching, module mixins, DSLs, define_method. The ninth card is the Matz philosophy that links them.
Everything is an Object
Ruby is more purely object-oriented than Java or Python — 1, nil, true, and class itself are all objects with methods. 1.times, nil.to_s, Class.new are all legal.
5.times { |i| puts i }
puts 5.class # => Integer
puts 5.class.class # => Class
puts nil.to_s # => ""Blocks and yield
Any method can take an anonymous code block ({ ... } or do ... end) and invoke it via yield. This is Ruby's core control-flow mechanism — each / map / open / transaction all ride on blocks.
def retry_3x
3.times do
return yield
rescue; next
end
end
retry_3x { fetch(url) }Symbols — :name
A Symbol is an immutable, interned identifier. :name has exactly one instance globally; hash lookup is faster than with Strings. Rails uses symbol keys everywhere: User.where(name: "Alice").
h = { name: "Alice", role: :admin }
h[:role] == :admin # identity compare
:foo.object_id ==
:foo.object_id # true — internedmethod_missing — runtime metaprogramming
When an object receives an undefined method, Ruby calls method_missing. ActiveRecord's find_by_email / find_by_age_and_role all hang off this hook. Hugely powerful — and a known cause of Rails slowness, so many modern uses switched to define_method at boot.
class Lazy
def method_missing(name, *args)
puts "called #{name}"
end
end
Lazy.new.foo(1) # called fooOpen classes & monkey patching
Ruby lets you add methods to any existing class, including core ones like String / Integer. Rails's 2.days.ago is a method added to Integer. Double-edged: elegant, but two gems can collide — hence the 2024 Namespace experiment aimed at controlled isolation.
class Integer
def days
self * 86_400
end
end
puts 2.days # => 172800Modules and include — mixin composition
Ruby has no multiple inheritance — instead, modules + include deliver the same goal. Enumerable is a module: any class that implements each can include it and gets map / select / reduce for free — "protocol via mixin".
class Deck
include Enumerable
def each
yield "♠A"; yield "♥K"
end
end
Deck.new.map(&:downcase)DSLs — domain-specific languages embedded in Ruby
Ruby has extremely low syntax noise (optional parens, trailing blocks, overloadable operators), making it a DSL paradise. Rails routing, RSpec, Capistrano, Sinatra — all DSLs. They read like config; they're actually Ruby code.
# RSpec — looks like English
describe User do
it "has a name" do
expect(user.name).to eq("Alice")
end
enddefine_method — synthesise methods at boot
Use define_method to generate methods at startup. Much faster than method_missing because the methods actually exist and hit the normal inline cache. Modern Rails idiom: metaprogramming, but resolved at boot.
class Role
%i[admin editor viewer].each do |r|
define_method("#{r}?") do
@role == r
end
end
endThe Matz Philosophy — Programmer Happiness
None of those eight idioms stand alone — they all serve one Matz line: "Ruby is designed for programmer happiness." Symbols make hash keys terse; blocks make callbacks read like sentences; monkey patching lets you reshape anything; DSLs let configuration be Ruby. This "subjective experience first" stance is rare in PL history, and it's the real reason Ruby has refused to die for thirty years.
"Ruby is not designed for the machine, and not for the business — it's designed for the human." — Matz
Why Ruby : WhyRuby
Ruby in 2026 isn't the hottest or the fastest, but six things keep it the lowest-moving-parts answer for mid-sized business web development: the Matz philosophy, English-like reading, convention over config, the Majestic Monolith, Shopify as patron, and Hotwire as the anti-SPA play.
Programmer happiness — Matz's explicit goal
Matz says it repeatedly: Ruby is designed to "make programmers happy." This is rare in PL history — a language whose stated design value is a subjective feeling. Ruby doesn't aim for the fastest or the strictest; it aims to read well, and lets YJIT handle the rest.
# Matz, repeatedly:
# "Ruby is designed to make
# programmers happy."Code that reads like English
Ruby makes method chains read like sentences: 5.times { ... }, users.select &.active?, article.published?. The "fluent" style is pushed to its limit by RSpec, Sidekiq and ActiveRecord — non-programmers can often guess what Ruby code is doing.
users.where(active: true)
.order(:created_at)
.limit(10)
.map(&:email)Convention over configuration
DHH baked the principle "most apps look alike — stop reinventing directory structures" into Rails in 2004. app/models, app/controllers, naming rules — follow the conventions and the framework works. The "experts picked the defaults" idea then influenced essentially every web framework that came after.
# Rails: zero config needed
class Article < ApplicationRecord
belongs_to :author
has_many :comments
endThe Majestic Monolith — anti-fragmentation
DHH publicly opposes microservices: "small teams running micro-services are courting pain." GitHub is a Rails monolith. Shopify is a Rails monolith. Basecamp is a Rails monolith — three $1B+ companies running on the architecture HN has been mocking for ten years. Rails 8's Solid Queue / Cache makes "start with Postgres, don't install Redis" the default.
# Rails 8 defaults — no Redis
# Solid Queue · DB-backed jobs
# Solid Cache · DB-backed cache
# Solid Cable · DB-backed pubsubShopify carries the compiler
Since 2015 Shopify has made Ruby/Rails core strategy and now employs ~1500 Ruby engineers, sponsoring YJIT, TruffleRuby, Sorbet and Tapioca. Maxime Chevalier-Boisvert (YJIT) works on it full-time at Shopify. Ruby is one of the few scripting languages with a seriously committed public-company patron — Python doesn't, JS only has the Node foundation.
# Shopify-backed projects:
# · YJIT (the JIT)
# · Sorbet (gradual types)
# · Tapioca (RBI generator)
# · TruffleRuby (GraalVM-based)Hotwire — Rails's anti-SPA answer
In 2020 37signals open-sourced Hotwire (Turbo + Stimulus): server-rendered HTML patched into the DOM over WebSocket. The claim "you don't need React to ship modern UX" turns out to be defensible. Hey, Basecamp and parts of GitHub run on it. HTMX then borrowed the same idea and stole the headline narrative in 2023.
# turbo_stream — patch DOM
turbo_stream.append("comments",
partial: "comment",
locals: { comment: c })Who's Using : RubyInProduction
The "Ruby is dead" rumour is an annual tradition, but the 2026 reality: GitHub is a Rails monolith; Shopify runs a Rails app behind $5B+ revenue; Stripe leans heavily on Ruby; Coinbase / Square / Instacart / GitLab / Airbnb / SoundCloud were all born on Rails. None of the twelve below is a historical list — they all generate revenue today.
DHH & the Rails Doctrine : One Man, One Stance
The Ruby language is Matz. Ruby's destiny is DHH. David Heinemeier Hansson didn't design Ruby, but he carried it out to the world via Rails, then defended it for twenty years with one of the most counter-mainstream stances in the industry. Without DHH, Ruby would still be a quiet Japanese language. This section is about him and his positions — they are the real driver of the Rails roadmap.
"Most small companies do not need micro-services, do not need Kubernetes, do not need React, do not need GraphQL, do not need TypeScript. What they need is a stack that lets five people ship a real product over five years. Rails has always been that stack — we just keep throwing out the unnecessary pieces.
DHH extracted Rails 0.5 from Basecamp and open-sourced it on July 24 — no corporate approval, no funding, no marketing team. One Danish developer, one Apple laptop, one screencast, and a five-year revolution (2005–2010) in web development followed.
DHH never left 37signals, never raised VC, never sold the company. Basecamp and Hey support a profitable business — full-stack Rails, remote, small team. The "anti-Silicon-Valley playbook" is itself a statement: you don't have to be a unicorn.
In 2020 37signals open-sourced Hotwire (Turbo + Stimulus): render HTML on the server, patch the DOM over WebSocket, write almost no JS. Hey.com and Basecamp 4 are both built on it. The assumption "you need React for modern UX" got a serious rebuttal for the first time.
What 37signals uses / refuses
Here is the actual stack at 37signals (Basecamp + Hey). Every "removed" entry is something DHH has publicly argued about — these are not omissions, they are positions.
Rails 8 (2024) makes Solid Queue / Solid Cache / Solid Cable default — explicitly to remove the Redis dependency. Kamal 2 brings Heroku-class deployment down to a bare Docker host. Each release is executing "one less layer".
turbo + stimulusTwitter left Ruby because it was slow — not really
After Twitter's "fail whale" went viral in 2008, "Ruby can't scale" became the dominant narrative — but the real story is much more layered. What actually happened: Twitter migrated its search back end to Scala (Finagle / Storm) starting in 2011, while the front-end web stayed on Rails into the 2020s. The whole migration took close to a decade.
The bottlenecks were Ruby 1.8's mark-and-sweep GC, the single-process model, and early ActiveRecord's N+1 + fan-out write patterns — the implementation choices of that era didn't fit 100M tweets/day; that has little to do with "the Ruby language." YARV in 1.9 and generational GC later fixed most of it.
Compare: GitHub over the same window (2008–2020) handled Twitter-class traffic on a Rails monolith, with no "we left Ruby" narrative — because GitHub's workload (git pushes, PRs) is fundamentally different from Twitter's fan-out timeline writes. A simple "Ruby is slow" line hides every one of those architectural differences.
# Twitter migration truth: layered + gradual
2008 fail whale meme
2011 search backend → Scala
2013 some services → Scala
2015 Ruby still front-end
2020 Rails finally retired
2022 Elon takeover, infra cut
# Same window, GitHub: one Rails, full site
2008 Rails 2 monolith
2015 same monolith, 100x traffic
2026 still RailsIn one line: DHH carried Ruby out to the world, then defended it for twenty years with a counter-mainstream stance. In the microservices era he doubled down on monolith; in the React era he doubled down on server-render; in the TypeScript era he removed TS. Whether he is right or wrong matters less than this: he has kept Ruby evolving in a non-mainstream but coherent direction, and the language hasn't been lost in each fashion cycle.
vs Python / JavaScript : Ruby vs Python vs JS
Versus Python (/code/python): a sibling scripting language (1991 vs 1995) that picked different design trade-offs. Versus JavaScript (/code/javascript): its main web-backend competitor — Node took the "fashionable web back end" slot from 2014 onward, but Rails still wins on business-complex mid-sized apps.
| Python | Ruby | JavaScript | |
|---|---|---|---|
| Origin | Guido · 1991 | Matz · 1995-12-21 · 日本 / Japan | Eich · 1995-05 · 10 days |
| Design ethos | "One obvious way" (Zen) | Programmer happiness (Matz) | "Ship the thing in 10 days" |
| Syntax flavour | Strict indent · one style | Minimal punctuation · multiple idioms allowed | C-family braces |
| Blocks / closures | Has lambdas / def — but not central | Blocks are central · do...end / {} | () => {} · first-class |
| Everything is an object | Mostly · but ints are C-boxed | Purely · 1.times / nil.to_s | Primitives vs Objects split |
| Metaprogramming | Modest · decorators + descriptors | Extreme · method_missing / define_method / open classes | Proxy · prototype mutation |
| Concurrency | GIL · multiprocessing · asyncio | GVL · multi-process + Fibers · experimental Ractor | Single-thread event loop · worker_threads |
| Performance (2026) | CPython slow · 3.13 free-threaded experiment | YJIT default · ~2.5× vs Ruby 2.7 | V8 JIT · perennial leader |
| Web framework | Django · Flask · FastAPI | Rails 8 (dominant) · Sinatra · Hanami | Express · Next · Hono · Remix |
| Package manager | pip + venv + poetry | Bundler (built-in, canonical) | npm / pnpm / yarn / bun |
| Type system | mypy / Pyright · optional | Sorbet / RBS · optional · never in core | TypeScript · near-mandatory |
| Primary audience | Data · ML · scripts · DevOps | Mid-sized business web back end | Frontend · full-stack · serverless |
| Governance | PSF · ex-BDFL · steering council | Matz BDFL + ruby-core + Shopify $ | TC39 committee · multi-vendor |
Outlook : TheRoadAhead
Ruby's real 2026 problem is no longer performance (YJIT solved it) or stability (the language is 33; libraries are mature). It's that the next generation isn't learning it. The four cards below tackle the perf tailwind, two parallel type efforts, the Ractor concurrency puzzle, and the hiring-market soft spot.
YJIT + Rails 8 — a compounding tailwind
Ruby's perf story is no longer a story in 2026 — YJIT is default, Rails workloads run 2.5×+ faster than they did on 2.7. Shopify reports ~9% CPU savings at 100% production traffic, and Rails 8's Solid Queue / Cache strip external dependencies — a single Postgres is enough to ship.
Combined, that means Ruby is no longer "the elegant but slow small language." For mid-sized businesses (10–1000 engineers), the monolith + Hotwire + YJIT stack is the lowest-moving-parts full-stack option of 2026.
Sorbet vs RBS — two roads to gradual typing
"Should Ruby get static types?" has been argued since 2.0. Two parallel efforts: Sorbet (Stripe, separate type checker, .rbi files) and RBS (official, in stdlib since Ruby 3.0, .rbs files). State in 2026: both coexist; Stripe / Shopify use Sorbet, the general gem ecosystem favours shipping RBS sigs. Ruby is not turning into TypeScript — Matz keeps saying types are optional and never enter the syntax.
Ractor & true parallelism
Ruby has lived with the GVL (Global VM Lock — Python's GIL by another name): one core per process. Ruby 3.0 introduced Ractor, an actor model with per-Ractor GC heaps, theoretically enabling multi-core. In 2026 Ractor is still experimental — many gems aren't ractor-safe. The mainstream concurrency story is still multi-process (puma / unicorn fork) + Fiber-based IO.
The real soft spot: the hiring market
Performance, ecosystem, stability — none of those are Ruby's problems in 2026. Hiring is. Younger engineers default to TS / Go / Rust; the Ruby/Rails job-listings curve has been flat for five years. Stack Overflow 2025 survey: Ruby still ranks in the top-20 most-loved, but its most-wanted ranking has steadily fallen. Ironically, Ruby-fluent people are scarce on the market and command above-average pay — but new entrants aren't learning it.