Mustermann 4.0 released!

By Konstantin Haase on Monday, April 27, 2026

13 years ago today I released the very first version of Mustermann.

It allows you to create Regexp-like pattern objects:

require "mustermann"

pattern = Mustermann.new("/hello/:name")

pattern =~ "/hello/world"      # => 0
pattern.params("/hello/world") # => {"name" => "world"}

This is what Sinatra uses to match routes and extract parameters from the request path.

Since then other projects besides Sinatra have started using Mustermann, which I think is fantastic, and it has been maintained by a great community of contributors over the years. I myself took a break from Mustermann from 2017 until two weeks ago!

Performance, performance, performance!

You can find the full list of changes in the changelog, but the really big highlight is a significant improvement in performance!

Important disclaimer: The numbers below reflect pattern matching and routing performance only! For a real world app, this is probably not a bottleneck. So take especially the framework benchmarks with a truckload of salt.

For individual patterns

Pattern creation is now 6 times faster than before, and matching individual patterns can be up to 3 times faster than before, assuming normal usage, and over 150 times faster for malicious input strings.

Here are preliminary results for hanami-router when upgrading Mustermann from 3.1.1 to 4.0.0, without any other changes:

hanami-router with Mustermann 3.1.1 vs 4.0.0
Lighter red: Hanami Router with Mustermann 3.1.1
Darker red: Hanami Router with Mustermann 4.0.0
Requests per second for an application with X routes, linear scales, higher is better.

And most of Hanami’s routing logic currently doesn’t even use Mustermann!

For sets of patterns

However, the biggest performance improvement is for sets of patterns. Mustermann 4 now comes with tooling to match against multiple patterns at once, at greatly improved performance. In my benchmarks matching against a set of 1000 patterns is more than 400 times faster than before, and the improvement grows with the number of patterns.

require "mustermann/set"

set = Mustermann::Set.new

set.add "/hello/:name"
set.add "/goodbye/:name"

result = set.match("/hello/world")
result.pattern # => #<Mustermann::Sinatra:""/hello/:name">
result[:name]  # => "world"

For convenience you can also attach arbitrary values to individual patterns.

set.add "/users/:id", controller: "users", action: "show"
set.match("/users/42").value # => { controller: "users", action: "show" }

As you might have spotted, this API is primarily intended for use within frameworks and libraries. So what’s the impact for end-users?

Here are experimental numbers for Sinatra patched to use this new feature:

Sinatra with Mustermann 3.1.1 vs 4.0.0 (using Mustermann::Set)
Lighter purple: Sinatra with Mustermann 3.1.1
Darker purple: Sinatra with Mustermann 4.0.0
Requests per second for an application with X routes, linear scales, higher is better.

However, in Sinatra’s case the performance improvement is still smaller than it could be for other uses, as routes need to be tried in definition order, and all matching patterns need to be tried, as you can use pass to skip to the next route.

With a very minimalistic implementation that doesn’t have these constraints, I’m seeing the following results (attention, this is a logarithmic scale):

Sinatra with Mustermann 3.1.1 vs Mustermann::Router
Purple: Sinatra with Mustermann 3.1.1
Blue: Mustermann Router
Requests per second for an application with X routes, logarithmic scales, higher is better.

More numbers

Pattern-only benchmarks:

Scenario 3.1.1 4.0.0 Improvement
Simple patterns Compilation 12.1 K/s 70.8 K/s 6x
Matching non-repeating strings 4.5 M/s 4.5 M/s
Matching repeating strings 5.9 M/s 17.1 M/s 3x
Extracting params 0.7 M/s 2.2 M/s 3x
Matching against 1k different patterns 7.1 K/s 3 M/s 425x
Complex patterns Extracting params 486 K/s 955 K/s 2x
Matching against malicious input 3.6 K/s 582 K/s 162x

Routing Rack requests (hot path scenario):

Router Mustermann 100 routes 1,000 routes 10,000 routes
Mustermann Router 4.0.0 1,544,163 req/s 1,500,825 req/s 1,338,151 req/s
Sinatra 3.1.1 28,544 req/s 24,659 req/s 19,042 req/s
Sinatra 4.0.0 38,256 req/s 38,052 req/s 37,750 req/s
Hanami Router 3.1.1 359,054 req/s 345,686 req/s 315,447 req/s
Hanami Router 4.0.0 463,865 req/s 447,507 req/s 419,410 req/s
Ruby on Rails 7,972 req/s 5,177 req/s 964 req/s
Roda 271,880 req/s 219,390 req/s 155,147 req/s

Benchmarks taken on my development machine (2024 MacBook Pro).

Again, keep in mind that these aren’t measuring full applications, nor going through the full HTTP protocol. So while these numbers are exciting, they don’t necessarily translate to a real world app.

All these frameworks also come with differing sets of features, that will impact performance in different ways. The Hanami measurements are only measuring hanami-router, and are thus more comparable to the numbers from Roda (without any plugins) or Mustermann::Router, which also only do Rack routing, and thus can’t be directly compared to Sinatra and Rails, which come with richer feature sets out of the box, as wall as a host of middleware to secure your application.

Rails and Roda are included for comparison, but they don’t use Mustermann. Rails has a similar tool to Mustermann called Journey and Roda uses nested Ruby blocks to mimic route structure.

So when can I use it?

Stand-alone

You can update to Mustermann 4.0 by changing your Gemfile:

gem "mustermann", "~> 4.0"

Or if you don’t use Bundler, you can install it with:

gem install mustermann -v "~> 4.0"

Sinatra

Sinatra (at least up to 4.2.1) depends on Mustermann 3. In theory it is already compatible with 4.0, as the breaking changes are minimal, but an updated Sinatra version that leverages Mustermann 4.0 more fully is currently under development. Once it’s released, you can update Sinatra to the latest version to benefit from the improvements in Mustermann 4.0.

Expect an updated Sinatra release in the next few weeks!

Hanami

Similar to Sinatra, Hanami depends on Mustermann 3.1. There is on-going work to figure out to what extent Hanami can leverage Mustermann 4.0. I’m working closely with the Hanami team, and this should be resolved in the next few weeks as well.

Grape

Update Mustermann (see above) and you should be good to go. Grape will automatically use the latest version of Mustermann available.