Rails assets

Propshaft versus Sprockets in Rails assets

A concise comparison of Rails asset pipelines: Propshaft's smaller modern contract versus Sprockets' older processing pipeline and compatibility surface.

Different contracts

Sprockets and Propshaft both serve Rails assets, but they make different promises. Sprockets is an older processing pipeline. Propshaft is a smaller modern asset pipeline built around digesting, serving, and referencing already-prepared files.

The comparison is not only old versus new. It is about where transformation should happen. If the application expects the asset pipeline to compile languages, process directives, concatenate files, and provide compatibility behavior, Sprockets has a larger historical contract.

If the application already uses modern JavaScript and CSS tooling outside Rails, Propshaft can be a cleaner fit because Rails no longer needs to pretend to be the whole frontend build system.

The Sprockets pipeline

Sprockets grew up when Rails applications commonly relied on the asset pipeline for concatenation, preprocessing, fingerprinting, dependency directives, and production compilation. It supported a world where CoffeeScript, Sass, ERB assets, and directive comments were normal.

That breadth is valuable for older applications. It means a legacy app may have many small asset behaviors that nobody thinks about until migration: require directives, asset helpers inside CSS, engine-provided assets, precompile lists, and processor gems.

The cost is complexity. The pipeline can feel magical because it owns both transformation and delivery.

The Propshaft contract

Propshaft narrows the contract. It fingerprints assets, resolves references, and serves from a load path. It expects that heavy transformation can happen before assets reach Rails, usually through tools such as bundlers, CSS processors, or plain authored files.

This makes the Rails side easier to reason about. Assets are files. They get digested. Helpers point at digested names. The pipeline is less involved in deciding how JavaScript and CSS are authored.

That simplicity is strongest in apps that have already moved away from Sprockets-specific processors and directive-based composition.

What changes in the app

The practical difference is that Propshaft assumes modern asset inputs and a simpler fingerprinting pipeline. It serves digested files and leaves bundling or transpilation to other tools when the application needs them.

<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_include_tag "application", type: "module", "data-turbo-track": "reload" %>

With Sprockets, many older apps also rely on directives inside manifest files and on the asset pipeline doing more transformation work.

//= require jquery
//= require_tree ./controllers
//= require_self

A migration should start by listing what the current pipeline actually does: fingerprinting, Sass, CoffeeScript, ERB in assets, image URL rewriting, vendored JavaScript, or concatenation. Propshaft is attractive when that list is already short or when bundling has moved to a dedicated tool.

Migration questions

Before switching, inspect what the current app actually uses. Search for Sprockets directives, ERB inside assets, Sass imports, engine assets, fonts referenced by relative paths, and any custom processors. The migration risk is in those details.

The question is not whether Propshaft can serve files. It can. The question is whether the app is still depending on Sprockets to build or rewrite those files in ways that have become invisible.

A careful migration removes or replaces those behaviors first, then switches the asset pipeline after the asset graph is already boring.

A good inventory includes generated filenames too. If CSS refers to images by relative path, or JavaScript expects a bundled vendor file to exist at a particular name, the migration needs to preserve those references or move them to helpers that understand digested assets.

The rollback plan should be explicit. Asset migrations often fail late, when a rarely used admin screen or email preview references an old pipeline behavior. Keeping the old branch deployable until those paths are checked makes the change much less risky.

For teams, the social part matters too: everyone should know whether new JavaScript belongs in a bundler, an import map, or a plain file served by Propshaft. Otherwise the app slowly recreates the old ambiguity under new names.

That clarity matters more than the name of the asset pipeline because explicit ownership makes missing build steps easier to diagnose.

Production shape

In production, either pipeline should produce cacheable, fingerprinted assets. The operational difference is where build failures happen and how much Rails participates in the build.

Propshaft pairs well with a production flow where JavaScript and CSS bundling are explicit steps and Rails mainly publishes the resulting files. Sprockets remains reasonable when an app's asset dependencies are still deeply tied to its processors.

The pragmatic rule is to choose the smaller contract that the application can honestly satisfy. New Rails apps often fit Propshaft. Older apps should migrate only after their asset assumptions are made visible.

How to review an app

The best migration review starts with inventory rather than preference. List every asset entry point, every file that uses Sprockets directives, every processor dependency, and every place CSS references images or fonts. That tells the team whether the app is already close to Propshaft's model or still depends on Sprockets behavior.

After that, test the compiled production assets, not only the development server. Fingerprinted paths, cache headers, font loading, source maps, and engine-provided files are the places where asset-pipeline assumptions usually surface.

Sources

  1. Rails Guides, Asset Pipeline. https://guides.rubyonrails.org/asset_pipeline.html
  2. Propshaft repository. https://github.com/rails/propshaft
  3. Sprockets repository. https://github.com/rails/sprockets