Library / SDK
rails/sprockets avatar
rails/sprockets

Sprockets: logical paths, header directives and a right to left processor chain

Rack-based asset packaging system

986 stars796 forksRubyMIT

At a glance

What is it?
Sprockets is the Ruby library that compiles and serves web assets for Rack based frameworks, and almost everything about it follows from two ideas: assets are addressed by logical path, and processors run from the rightmost extension to the left. The gotchas are documented, and they are the ones that cost you an afternoon.
Who is it for?
Adopt Sprockets when you are inside the Rails asset pipeline or another Rack framework that expects it, and when your assets are CoffeeScript, Sass or SCSS with a simple dependency graph. Do not pick it for a modern JavaScript build with bundling and tree shaking, because Sprockets concatenates rather than bundles and orders files alphabetically by default.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 59 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Assets are addressed by logical path, not by disk path

The single most important idea in Sprockets is that an asset is never named after the file on disk. It is named after its logical path, which is the path of the source file relative to the directory that contains it in the load path. If the load path includes `app/assets/javascripts`, then the source file `app/assets/javascripts/application.js` is requested as `application.js`, and `app/assets/javascripts/models/project.js` is requested as `models/project.js`.

The interesting case is the third row of that mapping: a file on disk called `hello.coffee` is requested as `hello.js`. The rule the README gives is that you ask for the extension you want, not the extension you have, because the asset that comes out is JavaScript.

This is the design that lets a framework own the directory layout. The load path is where the framework decides that JavaScript lives in one place and stylesheets in another, and the logical path is what your templates reference, so moving a file between framework directories does not break every reference to it. The cost is that a name in your HTML no longer tells you which file on disk produces it, and a typo in the extension produces a missing asset rather than a clear error, which is why the README suggests checking both the extension and the load path when an asset does not appear.

Directives are only read in the header of a file

Directives are the primary way to interact with processors, and they are comments. The classic case is a JavaScript file that depends on jQuery, which puts a require directive at the top:

js
//= require jquery

$().ready({
  // my custom code here
})

The processor understands comment blocks in three formats, one per language family. Multi-line comment blocks, used in CSS, SCSS and JavaScript:

``` css /* Multi-line comment blocks (CSS, SCSS, JavaScript) *= require foo */

code

Single-line comment blocks in SCSS and JavaScript:

js // Single-line comment blocks (SCSS, JavaScript) //= require foo

code

And single-line comment blocks in CoffeeScript:

coffee # Single-line comment blocks (CoffeeScript) #= require foo ```

The rule that catches people is about placement. The README is explicit that directives are only processed if they come before any application code, and that once a line appears that is neither comment nor whitespace, Sprockets stops looking for directives. The consequence is stated just as plainly: a directive placed outside the header of the document does nothing and raises no error. There is no warning, no exception and nothing in the log. If a file that should pull in a dependency does not, the first thing to check is whether the directive sits above the first line of real code.

Extensions decide the processor chain and it runs right to left

Sprockets picks processors from the filename extension. A file called `application.scss` runs the sass processor, which implements scss, and the output is CSS. A file can carry several extensions at once, and the order in which those processors run is fixed: from right to left, tail to head. Naming a file `application.scss.erb` means the erb processor runs before the scss processor, so ERB is evaluated first and the result is then compiled by sass.

code
application.scss
code
application.scss.erb

The same rule applies to what you ask for. When you request a compiled file you always request the extension you want, so the contents of `application.scss.erb` are fetched as `application.css`:

code
asset_path("application.css")

Sprockets understands that the chain compiles down to that extension. The README states the principle plainly: ask for what you need, not what you have.

Two details are worth keeping in mind. The default processor set ships with Sprockets, but other libraries may register additional processors, so the chain for a given extension set is not fixed by Sprockets alone. And when the mapping does not behave as expected, the README points at two things to verify, a typo in the extension and the load path, rather than at the processor itself.

Installing Sprockets and pinning the 4.x line

Sprockets installs from RubyGems:

``` sh $ gem install sprockets

code

Or it goes into a project Gemfile with Bundler, where the README pins the major series:

ruby gem 'sprockets', '~> 4.0' ```

The `~> 4.0` constraint is the interesting part. It permits any 4.x release while refusing 5.0, which is what you want from a library that a framework pins for you and that changes behaviour between major versions.

Most people meet Sprockets through another framework rather than by installing it directly. The README says so explicitly, and it redirects you to your framework's documentation for the configuration that decides which directories and files get compiled. That division matters when something does not compile: load paths, precompile lists and directories are framework settings, while logical paths, directives and processor chains belong to Sprockets itself.

The directive vocabulary splits inclusion from linking

The list of directives is longer than most people expect, and it divides into three groups that answer different questions.

The first group changes what ends up inside the current asset. `require` adds the contents of a file to the current one. `require_self` changes where the current contents are concatenated. `require_directory` adds the contents of each file in a folder, and `require_tree` does the same for a whole path of directories.

The second group is about compilation without inclusion. `link` makes a target file compile and become publicly available without adding its contents to the current asset, and `link_directory` and `link_tree` do that for a directory and a tree. This is the mechanism for shipping a separate script file that is not concatenated into your bundle but still needs to be built and served.

The third group is about invalidation. `depend_on` recompiles the current file if the target has changed, and `depend_on_directory` does the same when any file in a directory changes. The last directive, `stub`, ignores a target file entirely.

The distinction between require and link is the one to internalise, because the two look similar and behave differently. require inlines content into a bundle, link leaves the file separate and merely makes it available.

Alphabetical file order is the default and it will surprise you

By default, files are processed in alphabetical order, and the README is direct that this behaviour can affect your compilation when one asset needs to load before another.

The example is a directory included with a require_directory directive:

js
//= require_directory my_javascript

When the directory holds alpha.js, beta.js and jquery.js, the alphabetical order puts alpha.js first, and the README notes that this is what happens. If a plugin expects jQuery to be present when the earlier file runs, the alphabetical order loads it in the wrong sequence and the failure appears at runtime as a missing symbol rather than as a build error.

There are two ways out, and the directive vocabulary contains both. `require_self` controls where the current file's own contents are concatenated, which lets you control where your own code sits relative to the included files. And explicit `require` directives, or a deliberate rename, give you exact ordering. Neither is mentioned as a configuration knob in this README section, which suggests the ordering is a property of the asset graph rather than something you configure globally.

What changed in 4.x and where to read further

The README lists the headline features of Sprockets 4.x: source maps, Manifest.js, ES6 support, and the removal of the processor interface that was deprecated in 3.x. The removal is the item that bites during an upgrade, because code written against the old interface stops working rather than warning, and the README points to UPGRADING.md for the details.

The repository also organises its documentation by audience, which tells you something about who the project is for. There is a guide for framework developers building an asset processing framework, a guide for library developers extending Sprockets, and a guide for people working on Sprockets itself or wanting to understand how it works. Three audiences for one library is a sign of a mature, widely embedded component rather than a standalone tool.

Mechanically, the repository is a normal gem: a gemspec, a Gemfile, a Rakefile, lib/, test/, bin/, a .rubocop.yml and a CHANGELOG.md, plus a .devcontainer directory and an appveyor.yml. The licence is MIT, with the terms in the MIT-LICENSE file at the root, which is the permissive end of the spectrum and carries no copyleft obligation for the applications that embed it.

On maintenance, the picture is a stable library with an uneven release history. The releases listed are v4.2.0 and v4.2.1, both on 2023-09-05, and v4.2.2 on 2025-08-19. The repository is not archived and the last push was on 2026-08-25, so work continues on the main branch, but the gap between the last release and the last commit is the number to keep in mind when you pin a version.

Editorial conclusion

Adopt Sprockets when you are inside the Rails asset pipeline or another Rack framework that expects it, and when your assets are CoffeeScript, Sass or SCSS with a simple dependency graph. Do not pick it for a modern JavaScript build with bundling and tree shaking, because Sprockets concatenates rather than bundles and orders files alphabetically by default. Before upgrading to 4.x, read UPGRADING.md for the removed processor interface, and note that the last push was on 2026-08-25 while the newest release is v4.2.2 from 2025-08-19.

Frequently asked questions

How do I install Sprockets in a Ruby project?

Install it from RubyGems with gem install sprockets, or add gem 'sprockets', '~> 4.0' to your Gemfile and use Bundler.

Why is my require directive ignored in a Sprockets asset?

Directives are only processed before any application code. Once a line that is not a comment or whitespace appears, Sprockets stops looking for directives, and a misplaced directive does nothing without raising an error.

In what order do Sprockets run processors for application.scss.erb?

Processors run from right to left, so the erb processor runs before the scss one. You request the result with the extension you want, for example asset_path("application.css").

What is the difference between require and link in Sprockets?

require adds the contents of the target file into the current asset, while link makes the target compile and become publicly available without adding its contents to the current asset.

Official sources

  1. Issues
  2. License: MIT
  3. rails/sprockets on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rails-sprockets.svg)](https://hysenlabs.com/projects/rails-sprockets)