# FasterPath: a faster Pathname for Ruby, written in Rust

> FasterPath is a Ruby gem that reimplements Ruby's Pathname on top of a Rust extension, aimed at Rails applications where path handling dominates request time. The performance claims in the project come from one developer's own application profile, and the gem is documented against Sprockets 2 rather than Sprockets 3, which narrows where the numbers apply.

**danielpclark/faster_path** — Faster Pathname handling for Ruby written in Rust

- Repository: https://github.com/danielpclark/faster_path
- Stars: 775 · Forks: 29
- Language: Ruby
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/danielpclark-faster-path

## chop_basename is the method the whole pitch rests on

The stated goal of the project is narrow and specific: path relation and file lookup is a bottleneck in Ruby, so the work targets the most heavily used areas. The author found this by profiling a Rails application after a Sprockets 3 upgrade made his site load 31.8% slower than the 2.0 series, and by counting which methods were called most often.

The headline improvement is attributed to one method, chop_basename. The author describes how the first release had a bug in which that method immediately returned nothing, and how the useful side effect of that bug was diagnostic: the Rails test suite still passed, the assets stopped loading, and the pages loaded just more than 66% faster without the time chop_basename had been consuming.

From that, the project derives the central claim, that path handling for assets consumes more than two thirds of a website's page load time. The improvement figure quoted for chop_basename is 83.4%, up from just over 50% in the original release, and the projected overall gain of 55.044% is explicitly conditioned on the reader having a similar performance profile. These are the author's numbers from his own application, not a published benchmark, and the project documentation does not describe any reproducible measurement harness.

## The call counts that motivated the rewrite

The profile output included in the README is what makes the case concrete, and it is a stackprof CPU dump from a Rails stack. The excerpt shows the boot line for a development endpoint and a hundred requests, followed by the sampled frames:

```bash
Booting: development
Endpoint: "/"
       user     system      total        real
100 requests 26.830000   1.780000  28.610000 ( 28.866952)
Running `stackprof tmp/2016-06-09T00:42:10-04:00-stackprof-cpu-myapp.dump`. Execute `stackprof --help` for more info
==================================
  Mode: cpu(1000)
  Samples: 7184 (0.03% miss rate)
  GC: 1013 (14.10%)
==================================
     TOTAL    (pct)     SAMPLES    (pct)     FRAME
      1894  (26.4%)        1894  (26.4%)     Pathname#chop_basename
      1466  (20.4%)         305   (4.2%)     Pathname#plus
      1628  (22.7%)         162   (2.3%)     Pathname#+
       234   (3.3%)         117   (1.6%)     ActionView::PathResolver#find_template_paths
      2454  (34.2%)          62   (0.9%)     Pathname#join
        57   (0.8%)          52   (0.7%)     ActiveSupport::FileUpdateChecker#watched
       760  (10.6%)          47   (0.7%)     Pathname#relative?
       131   (1.8%)          25   (0.3%)     ActiveSupport::FileUpdateChecker#max_mtime
        88   (1.2%)          21   (0.3%)     Sprockets::Asset#dependency_fresh?
        18   (0.3%)          18   (0.3%)     ActionView::Helpers::AssetUrlHelper#compute_asset_extname
       108   (1.5%)          14   (0.2%)     ActionView::Helpers::AssetUrlHelper#asset_path
```

A second listing counts call volume from Rails boot to the home page, where Pathname#to_s is called 29172 times, Pathname#<=> 24963 times and chop_basename 24456 times. The author notes the home page has minimal content, which is the point: the cost is in the framework and gems rather than in the page.

## A Rust crate exposed to Ruby through rutie

The implementation is a Rust library crate built as a cdylib, with a Ruby gem wrapping it. The crate manifest in the repository root describes the shape of the project exactly:

```toml
[package]
name = "faster_path"
version = "0.5.0"
authors = ["Daniel P. Clark <6ftdan@gmail.com>"]
description = "Alternative to Pathname"
homepage = "https://github.com/danielpclark/faster_path"
repository = "https://github.com/danielpclark/faster_path"
license = "MIT OR Apache-2.0"
readme = "README.md"
edition = "2021"
[lib]
name = "faster_path"
crate-type = ["cdylib"]
[dependencies]
rutie = "0.13.1"
memchr = "2"
```

Two dependencies do the work. rutie is the bridge that exposes Rust functions to Ruby, which is what lets the gem present a Pathname-shaped API backed by native code. memchr is the byte search crate, and it matters because the expensive operations here are string scans over path fragments.

The repository layout matches a mixed Ruby and Rust project: lib/, spec/ and test/ for the Ruby side, src/ and ext/ for the Rust and native extension parts, alongside a Gemfile, Rakefile, faster_path.gemspec and a .rustfmt.toml. The crate targets edition 2021 and declares its license as MIT OR Apache-2.0, while the gem side ships an MIT-LICENSE.txt at the root.

## Refinement, monkeypatch, or write against the library directly

Adoption comes in three forms, and the author is opinionated about the trade-off. You can write your application against FasterPath directly, or you can refine the existing standard library, or you can monkeypatch it. The README's phrasing on this is direct: refinements are narrowed in scope, and monkeypatching is called a sledge hammer.

That is a design decision worth respecting, because Pathname is used everywhere in a Rails application. A refinement confines the change to the lexical scope that activates it, so the blast radius is visible in the source. A monkeypatch changes Pathname for the entire process, including for gems that never opted in, which makes debugging a regression much harder. Writing against the library directly avoids both but touches every call site.

The stated direction of the project also goes beyond the Pathname class. The author expects path performance work to extend into related methods and classes rather than stopping at Pathname itself, so the surface area of the gem is expected to grow.

## Sprockets 2 is the precondition for the stated gain

The most important limitation in the project is stated plainly, and it is a version constraint on your asset pipeline. The README says you will likely need the Sprockets 2.0 series to see the best results in Rails, and that otherwise the library would need to rewrite Sprockets itself.

The reason is architectural. Pathname is heavily used in Sprockets 2, while in Sprockets 3 the project switched to calling Ruby's faster methods from File#initialize and Dir#each, having written the path handling themselves in Ruby. The author argues they gained some performance by switching to rawer code methods and then lost more than that through the many method calls built on top.

The dependency versions that accompanied the author's two test groups are listed, and they are old enough to date the experiment: the Sprockets 2 group used sprockets 2.12.4, sass 3.2.19 and bootstrap-sass 3.3.4.1, while the Sprockets 3 group used sprockets 3.6, sass 5.0.4 and bootstrap-sass 3.3.6. The data is based on method call counts rather than source code, as the author notes.

This makes the gem a poor fit for a modern Rails app and a good fit for a legacy one, which inverts what you might expect from a performance tool.

## Two version lines, and a release trail that stopped in 2018

The version numbers in this repository tell two different stories. The tagged releases listed for the project are v0.3.10 from 2018-03-30, v0.3.9 from 2018-03-14 and v0.3.8 from 2018-03-12, and the project page carries a commits-since-last-release badge anchored to v0.3.10. The crate manifest, however, declares version 0.5.0. A Ruby gem consumer and a Cargo consumer of this project are therefore looking at different version lines.

That gap has a practical consequence. Installing through RubyGems gives you the 0.3.x series, and the release history offers nothing newer to compare it against. The repository is not archived, and the last push was on 2026-10-21, so work continues on master without new tags.

On licensing, the situation is straightforward. The crate is MIT OR Apache-2.0, which is a permissive dual grant, and the gem side carries MIT-LICENSE.txt. Both licences are business friendly, but note the split: the Rust source and the gem wrapper carry their own terms, and the licence file the project ships is the MIT one. Nothing in the documentation discusses relicensing, and the project does not state who maintains the gem releases.

## Conclusion

Adopt FasterPath if you run a Rails application on the Sprockets 2 series, can measure a Pathname hotspot in your own stack profile, and want a drop-in Pathname replacement with a Rust extension rather than a rewrite. Do not adopt it if you are on Sprockets 3, where the project says the asset pipeline avoids Pathname and would need rewriting, or if you need a maintained release trail, since the newest tagged gem is v0.3.10 from 2018 while the crate manifest declares version 0.5.0. Before you try it, take a stackprof of your own application and check how much of your request time sits in Pathname#chop_basename, because that is the only method the stated gain is attributed to.

## FAQ

### What is FasterPath and what problem does it solve?

FasterPath is a Ruby gem that reimplements Ruby's Pathname class on top of a Rust extension, written to reduce the cost of path relation and file lookup in Rails applications. The stated benefit is a faster Pathname#chop_basename, which the author measured as a large share of request time.

### Does FasterPath work with Sprockets 3?

The README says you will likely need the Sprockets 2.0 series to see the best results, because otherwise the library would need to rewrite Sprockets itself. Sprockets 3 moved away from Pathname toward File#initialize and Dir#each, so the Pathname hotspot the gem targets is largely gone there.

### How is FasterPath built, and what does it depend on?

The Rust crate is named faster_path, targets edition 2021, is built as a cdylib and depends on rutie 0.13.1 to expose Rust to Ruby and on memchr 2 for byte searching. The repository combines lib/, spec/ and test/ with src/ and ext/, plus a Gemfile, Rakefile and faster_path.gemspec.

### Should I use FasterPath as a refinement or a monkeypatch?

The project presents three options: write the application against FasterPath directly, refine the standard library, or monkeypatch it. Its own position is that refinements are narrowed in scope while monkeypatching is a sledge hammer, so the narrower option is the one the author considers safer.

### What licence does FasterPath use?

The Rust crate manifest declares MIT OR Apache-2.0, a permissive dual grant, and the gem side ships an MIT-LICENSE.txt file at the root of the repository. The two sides of the project carry their own terms, so read the file that ships with the component you install.

## Sources

- [danielpclark/faster_path on GitHub](https://github.com/danielpclark/faster_path)
- [Issues](https://github.com/danielpclark/faster_path/issues)
- [License: MIT](https://github.com/danielpclark/faster_path/blob/master/LICENSE)
- [README](https://github.com/danielpclark/faster_path/blob/master/README.md)
- [Releases](https://github.com/danielpclark/faster_path/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/danielpclark-faster-path
