LaunchKit
← All posts
· 8 min read · by The LaunchKit team · 9 views

How many times has Rails been downloaded

The honest answer is about 800 million, and the reason it is not a precise number is more interesting than the number.

Everything below came out of the RubyGems.org public API on 2026-10-12, which needs no key and answers immediately. The script that produces all of it is at the bottom and it was run to write this page.

The number

$ curl -s https://rubygems.org/api/v1/gems/rails.json | ruby -rjson -e 'puts JSON.parse($stdin.read)["downloads"]'
799556317

799,556,317 downloads of the gem named rails, since RubyGems.org started counting.

That is the number to quote if somebody asks. The rest of this page is why you should quote it with "about" in front of it.

Which gem is Rails

rails is a meta gem. It depends on the pieces and contains almost no code of its own, so counting it counts the people who put gem "rails" in a Gemfile, and nothing else.

Gem Downloads Against rails
activesupport 1,449,172,900 1.81x
activerecord 849,395,593 1.06x
actionpack 837,332,406 1.05x
rails 799,556,317 1.00x
railties 798,557,373 0.9988x

Three of the five components have been downloaded more often than Rails itself, which is the part worth sitting with. activesupport is nearly twice as popular as Rails, because a large part of the Ruby ecosystem depends on it without being a Rails application: test frameworks, Sinatra apps, standalone scripts that want 3.days.ago.

So "how many times has Rails been downloaded" has at least two defensible answers, 800 million and 1.4 billion, and they differ by a factor of 1.81 depending on where you draw the line around the word Rails.

railties is the useful one. It holds the framework's boot and generators, nothing depends on it except Rails, and it comes in at 0.12 percent below rails. That near identity is a sanity check: the two numbers were produced by the same installs.

Ruby and curl do not agree

This is the finding that decided how precise this page is allowed to be.

One RubyGems API URL asked by two clients returns two different download totals. curl sends no Accept-Encoding header and is served the identity copy, which reads 799,556,317. Ruby's Net::HTTP sends an Accept-Encoding header asking for gzip and is served the gzip copy, which reads 799,552,821, a difference of 3,496. The response carries vary Accept-Encoding, so the two copies are separate cache objects ageing on separate clocks, and the same curl with the compressed flag crosses over to the Ruby number.

--- curl, no compression ---
799556317
799556317
--- curl --compressed ---
799552821
799552821
--- ruby, Net::HTTP ---
799552821
799552821
799552821

Same endpoint, same minute, two stable answers 3,496 apart.

The cause is one response header:

$ curl -sI https://rubygems.org/api/v1/gems/rails.json | grep -iE 'vary|age|cache-control|x-cache'
cache-control: max-age=60, public
age: 878
x-cache: HIT
vary: Accept-Encoding

vary: Accept-Encoding means the CDN stores a separate copy per encoding. Ruby's Net::HTTP sends accept-encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3 by default and curl sends none, so the two clients land on two different cache objects, each ageing on its own clock. curl --compressed moves curl onto Ruby's copy and the numbers match again.

The second header is the one that matters more. max-age=60 with age: 878 means the copy being served is fourteen minutes old against a sixty second instruction. Any reading is a snapshot of unknown staleness, and two readings taken a minute apart can go down, which is what happened first and is what sent me looking.

None of this is a bug worth reporting. It is the ordinary behaviour of a cached public API, and it is the reason a download count is a magnitude rather than a measurement.

The shape of eight hundred million

521 versions are listed, 347 stable and 174 prereleases. Summed, they come to 799,551,451, which reconciles with the gem total to within about a thousand, the two having been read from different cache copies.

The distribution is not what you would guess.

Version Released Downloads
4.2.0 2014-12-20 41,175,739
7.2.2.1 2024-12-10 19,730,578
5.2.8.1 2022-07-12 16,048,107
4.2.9 2017-06-26 14,397,799
5.2.3 2019-03-28 14,071,707
5.1.7 2019-03-28 13,976,786
7.1.5.1 2024-12-10 12,922,594
8.1.3 2026-03-24 12,776,335

4.2.0 is 5.1 percent of every Rails download there has ever been, on its own, and it is more than twice the next entry. A single release from December 2014 outweighs the entire 8.1 line so far.

Two things produce that. Long lived applications pinned to a version keep redownloading it on every cache miss for a decade, and 4.2 was the version a very large number of applications stopped on before the 5.0 upgrade. The security patch releases clustering in the table, 7.2.2.1 and 7.1.5.1 both on 2024-12-10, are the same effect compressed: a CVE lands, every pipeline in the world bundles on the same afternoon.

Which is also the warning. This column measures bundler activity, not adoption, and the two are only loosely related.

The dead end: the API does not know when Rails shipped

The obvious next question is when each version came out, and created_at looks like the answer.

It is not, for anything old:

-- the oldest numbers in the list --
   0.8.0        created_at 2009-07-25
   0.8.5        created_at 2009-07-25
   0.9.0        created_at 2009-07-25
   0.9.1        created_at 2009-07-25

Rails 0.8.0 was not released in July 2009. 46 of the 521 versions carry that exact date, everything from the 0.x line through 2.3.1, because that is the day RubyGems.org imported the back catalogue. Across 521 versions there are only 288 distinct dates.

So created_at is the date RubyGems.org learned about a version, which for everything from 2009 onward is also its release date, and for everything before it is one flat lie shared by 46 rows. Any chart of Rails releases built from this field has a vertical wall in 2009 and nothing before it.

For dates before 2009 the API is the wrong source, and the tags in rails/rails are the right one. From 2019 onward the field is trustworthy, which is what makes it usable for the question people actually ask of it: When is Rails 8.2 coming out.

What a download is not

Worth saying plainly because the number invites the wrong conclusion.

It is not users, it is not applications, and it is not installs. It is one HTTP fetch of a .gem file. Every CI run with a cold cache counts. Every docker build without a mounted bundle counts, once per layer rebuild. Every corporate mirror that pulls the whole index counts. A single team deploying forty times a day can generate more downloads in a week than a hundred hobby projects generate in a year.

The number is real, large, and tells you that Rails is widely used. It does not tell you how widely, and nobody has that number.

The script

Every figure above comes out of this. It needs no credentials.

require "net/http"
require "json"

def api(path)
  JSON.parse(Net::HTTP.get(URI("https://rubygems.org/api/v1/#{path}")))
end

%w[rails railties activesupport activerecord actionpack].each do |name|
  gem = api("gems/#{name}.json")
  printf("%-14s %15s   latest %s\n",
         gem["name"],
         gem["downloads"].to_s.reverse.scan(/\d{1,3}/).join(",").reverse,
         gem["version"])
end

versions = api("versions/rails.json")
summed   = versions.sum { |v| v["downloads_count"] }
top      = versions.max_by { |v| v["downloads_count"] }

puts
puts "versions listed        #{versions.size}"
puts "sum of every version   #{summed}"
puts "biggest single version #{top['number']} at #{top['downloads_count']} " \
     "(#{(100.0 * top['downloads_count'] / summed).round(1)}%)"
puts "distinct created_at    #{versions.map { |v| v['created_at'][0, 10] }.uniq.size}"
puts "oldest created_at      #{versions.map { |v| v['created_at'][0, 10] }.min}"

Run it and the totals will not match this page, because the counter moves and because your HTTP client decides which cached copy you get. That is the point.

What this page does not cover

Nothing here is adoption. The RubyGems API counts fetches and has no opinion about how many applications are running, how many developers are employed on them, or how that compares to any other framework, and the download counts of two ecosystems are not comparable at all: npm packages are fetched per dependency tree per install, which inflates them against a Ruby meta gem by orders of magnitude.

The per day and per version time series that would show whether that 800 million is still growing is available from a different endpoint and was not touched, so this page is a level and not a trend. Nothing was read from rails/rails itself, so the pre 2009 release dates named as missing above are named as missing and were not recovered.

#rails #ruby #tooling

Comments

No comments yet. Be the first.

Only used to confirm and publish your comment. Never shown publicly, never shared.

Markdown: **bold**, `code`, ```fenced blocks```, > quotes, [links](url). HTML and images are not rendered.