rails_performance puts APM dashboards in your own Rails app and Redis
Monitor performance of you Rails applications (self-hosted and free)
At a glance
- What is it?
- rails_performance is a MIT licensed Rails engine that tracks p50, p90 and p99 response times, slow requests, SQL queries, background jobs and system metrics, storing everything in a Redis you run yourself. It suits teams who want APM without sending production data to a third party, and it is a dashboard rather than a tracing system.
- Who is it for?
- Adopt rails_performance if you want response time percentiles, slow request reports, SQL visibility and background job timing without a third party APM, and if you are willing to run Redis and to protect the dashboard route yourself. Do not adopt it expecting distributed tracing, per-span profiling or the alerting of a commercial APM, because the feature list stops at request level metrics and reports.
- 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 123 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 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The dashboard is a Rails engine mounted into your own application
rails_performance is a self-hosted tool to monitor the performance of a Ruby on Rails application, and the README calls it a simple and free alternative to the New Relic APM, Datadog or other similar services.
The architectural choice is what distinguishes it. The gem is a Rails engine that mounts inside your application, so the dashboard is a route in the same app, at /rails/performance by default. There is no separate agent, no separate server, and no separate UI to authenticate against. The configuration confirms it, with config.mount_at defaulting to '/rails/performance' and a comment noting that alternatively you can mount the RailsPerformance::Engine in your routes.rb.
The engine route has one important consequence, and the README flags it immediately. The dashboard inherits your application's stack, so a slow query in your dashboard is a slow query in your app, and a deployment that is struggling will have a struggling dashboard. The upside is that everything works with one Redis, one app and one deploy.
The data goes to Redis and nowhere else. The README states that all data are stored in local Redis and not sent to any third party servers, and the configuration takes a Redis instance directly, either a plain connection or a namespaced one such as Redis::Namespace.new("rails-performance", redis: Redis.new).
That last point is the reason the tool exists for a lot of teams. APM products are the easiest part of an observability stack to justify internally and the hardest to get past legal and compliance review, because request data contains URLs, user identifiers and sometimes tokens. A gem that writes to your own Redis never has that conversation.
You must have Redis installed, the README says so plainly, because the gem stores data there.
Percentiles, slow requests and SQL, with the report tabs configured separately
The newer version of the tool adds the reporting that people actually miss in a home-grown setup, and the configuration exposes each report as its own set of options.
The Recent tab is real-time monitoring, and it has a time window and a limit of requests, configured through recent_requests_time_window and recent_requests_limit, both commented out in the default configuration, with a limit of nil or 1000.
The Slow Requests tab has three settings of its own: slow_requests_time_window, which is the window the slow requests are drawn from, slow_requests_limit, the maximum number of rows, and slow_requests_threshold in milliseconds. So what counts as slow is a number you set rather than a fixed constant, which is the difference between a report that is useful on a staging environment and one that is useful on production.
Beyond that the feature list is long. You can see p50, p90 and p99 response time. You get an average response time and a throughput report showing requests per minute. There is a report of the slowest controllers and actions. Total duration is broken down per request, per view rendering and per database time. SQL queries and rendering logs appear in the Recent Requests section. There are simple 500-crash reports, deployment events or custom events, and reports for Sidekiq jobs, Delayed Job jobs, Grape APIs inside a Rails app, and Rake task performance.
That list spans the whole request lifecycle, which is what makes the tool more than a response time graph. The one that is most often missing elsewhere is the breakdown of time spent in the view versus the database, because that is the measurement that tells you whether a slow endpoint is a slow template or a missing index.
Custom events are wrapped in a RailsPerformance.measure block, which is the hook for timing something that is not a request, a job or a rake task.
Instrumentation covers the background work, not just the web requests
The most useful thing about this tool for a real application is that it does not stop at the controller.
Sidekiq jobs and Delayed Job jobs are both instrumented, which is where a substantial part of an application's real work happens and where a request-level APM usually goes quiet. Rake tasks are timed too, and the configuration has both sides of that. config.skipable_rake_tasks defaults to ['webpacker:compile'], so asset compilation is excluded from the measurements by default, and config.include_rake_tasks is available to turn the monitoring on for the tasks you care about.
Grape API inside a Rails app is covered as well, which matters for the common setup where a Rails application also exposes a JSON API and you want one view of both.
The custom data hook is the extension point for anything the tool does not know about. config.custom_data_proc is a proc that runs inside middleware with access to the Rack env, and the README shows capturing the current user and the HTTP user agent:
# config.custom_data_proc = proc do |env|
# request = Rack::Request.new(env)
# {
# email: request.env['warden'].user&.email, # if you are using Devise for example
# user_agent: request.env['HTTP_USER_AGENT']
# }
# endThe proc runs inside middleware, which means it sees the raw Rack environment rather than a Rails controller, so anything in the request cycle is reachable. The example comment mentions Devise, and the ignored_endpoints and ignored_paths options exist so that a request can be excluded from the measurements entirely, by controller and action name in standard Rails notation, or by the beginning of the path, for example all routes starting with '/admin'.
System resources are a separate optional feature. You can monitor CPU, memory and disk by adding a required gem, and config.system_monitor_duration controls the window, with 24.hours as the example. That data is what turns a slow request report into a diagnosis, because a CPU that is saturated explains a p99 that has nothing to do with the endpoint.
The chart and table output is rendered in the application time zone, and the README explains you set that in config/application.rb with config.time_zone, defaulting to UTC when it is not set.
The dashboard is a predictable path, so it has to be protected
The security question for this gem is the same question as for any mounted dashboard, and the README addresses it directly.
It says to protect the performance dashboard with http basic auth or a check of current_user, and the configuration offers both. The HTTP basic authentication options are config.http_basic_authentication_enabled, which defaults to false, config.http_basic_authentication_user_name, and config.http_basic_authentication_password. The default credentials in the file are rails_performance and password12, which is fine as a placeholder in a generated initializer and completely wrong to leave in production.
The other option is the more flexible one. config.verify_access_proc is a proc that receives the controller, and the README gives both a permissive example and a realistic one:
# if you need an additional rules to check user permissions
config.verify_access_proc = proc { |controller| true }
# for example when you have `current_user`
# config.verify_access_proc = proc { |controller| controller.current_user && controller.current_user.admin? }The default is the permissive proc, which means the generated configuration does not protect anything. That is a reasonable default for a development environment and a real exposure in production, and it is worth noting that the performance data itself is sensitive: slow request reports and SQL logs describe your application internals, and the ignored_paths option demonstrates that the tool can be told to ignore /admin paths, but nothing stops the dashboard from being public.
There is also a mounting alternative for the cases where the default route does not fit, for example when company policy or an authentication scheme such as Devise means you want to control the mount. The README shows mounting the engine inside an authenticate block:
# config/routes.rb
Rails.application.routes.draw do
...
# example for usage with Devise
authenticate :user, -> (user) { user.admin? } do
mount RailsPerformance::Engine, at: 'rails/performance'
end
endWith that approach you can skip the mount_at and http_basic_authentication settings. The README also warns that under certain constraints such as subdomains it may be necessary to set url_options in the config so the engine can generate links correctly.
Install is a gem, a generator and a Redis
The installation is the standard Rails gem path, and the README gives the whole sequence.
The Gemfile entry is:
gem 'rails_performance'
# or
group :development, :production do
gem 'rails_performance'
endThe grouped form is the interesting one, because it shows the intended deployment shape. The gem is meant to run in production as well as development, otherwise the p99 numbers would only describe your laptop. That also means it belongs in the group where it should run, and the group is a deployment decision rather than a development convenience.
Then the bundle:
$ bundleAnd the generator that creates the default configuration file:
$ rails generate rails_performance:installThat produces config/initializers/rails_performance.rb, which the README says to look at and adjust. Redis has to be installed separately, since the gem stores data in it.
After that you start the application, make a few requests, and open https://localhost:3000/rails/performance.
The usage summary at the top of the README is the same thing in five lines: add the gem to the Gemfile in the appropriate group, start the rails server, make a few requests, open localhost:3000/rails/performance, then tune the configuration and deploy to production. The order matters slightly, because the dashboard is empty until the app has served some traffic.
The gem is described as production-ready, with the author's own experience quoted as two applications with around 800 unique users per day where it works perfectly. That is a useful calibration of scale, and it is also a modest one: the percentile machinery is the same at any scale, but the Redis memory footprint and the dashboard's own query cost grow with the request rate, and the default config.duration of 4.hours is the window over which data is kept.
MIT licensed, version 1.6, and a wide compatibility range
The licence is MIT, with the MIT-LICENSE file in the repository as the authoritative text, and this is a licensing statement rather than legal advice. There is no copyleft obligation on the applications that use it.
The releases are 1.6.0 on 2025-10-29, 1.5.2 on 2025-09-13 and 1.5.0 on 2025-08-28. The repository is not archived and the last push was on 2026-06-22, so the work continues on the master branch.
Compatibility is the other thing worth knowing, and it is unusually wide for a monitoring gem. The README says it works with Rails 4.2 and later, and probably 4.1 and 4.0 too, and Ruby 2.2 and later. That claim is what makes the gem interesting to an organisation with older applications, since the usual alternative in that situation is a hosted agent you cannot install.
The repository layout is a normal gem. There is a rails_performance.gemspec, an Appraisals file for testing against multiple dependency sets, a gemfiles/ directory to match, a lib/ directory for the gem code, an app/ directory for the engine's views and assets, config/, test/, bin/ and a Rakefile, plus a CHANGES.md for the changelog and a docs/ directory holding the screenshots the README embeds.
The project's ecosystem is worth a mention because it shows the audience. The README links RailsJazz and a cheatsheets site, both from the same author, and the repository is styled as a small set of independent tools rather than a company product. The topics on the repository list apm, datadog, newrelic, performance, performance-monitoring, rails, ruby and ruby-on-rails, which is an accurate description of a self-hosted alternative to those services.
One practical caveat comes from the design rather than the code. Because the dashboard is mounted in your application and the data lives in the same Redis, the tool is only as available as your app and as private as the route you expose. A tool that keeps data in-house is also a tool that you now have to operate.
Editorial conclusion
Adopt rails_performance if you want response time percentiles, slow request reports, SQL visibility and background job timing without a third party APM, and if you are willing to run Redis and to protect the dashboard route yourself. Do not adopt it expecting distributed tracing, per-span profiling or the alerting of a commercial APM, because the feature list stops at request level metrics and reports. Before you enable it in production, set a verify_access_proc or enable HTTP basic authentication, because the dashboard mounts at a predictable path and the README explicitly asks you not to forget that.
Frequently asked questions
How do I install rails_performance?
Add gem 'rails_performance' to the Gemfile, run bundle, then run rails generate rails_performance:install to create config/initializers/rails_performance.rb. You must have a Redis server installed, because the gem stores its data there, and you configure the Redis connection inside the RailsPerformance.setup block.
How do I protect the rails_performance dashboard?
The README says to protect the performance dashboard with http basic auth or a check of current_user. You can set config.http_basic_authentication_enabled to true with a user name and password, or set config.verify_access_proc to a proc that receives the controller, or mount RailsPerformance::Engine yourself inside an authenticate block in routes.rb.
What does rails_performance track besides response times?
The feature list includes p50, p90 and p99 response time, throughput in requests per minute, average response time, the slowest controllers and actions, total time per request, view rendering and database, SQL queries and rendering logs in Recent Requests, 500-crash reports, deployment events, Sidekiq jobs, Delayed Job jobs, Grape APIs, Rake tasks and custom events measured with a RailsPerformance.measure block.
Where does rails_performance store its data?
In Redis, configured on the config.redis setting, which can be a plain Redis instance or a namespaced one such as Redis::Namespace.new("rails-performance", redis: Redis.new). The README states that all data are stored in local Redis and are not sent to any third party servers.
Which Rails and Ruby versions does rails_performance support?
The README says it works with Rails 4.2 and later, and probably 4.1 and 4.0 too, and Ruby 2.2 and later. The recent releases are 1.6.0 on 2025-10-29, 1.5.2 on 2025-09-13 and 1.5.0 on 2025-08-28.
Official sources
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.
[](https://hysenlabs.com/projects/igorkasyanchuk-rails-performance)Was this useful?