- Introduction
- Features
- Screenshots
- Getting Started
- Authentication
- Tagging System
- Data Management
- Separate Database Support
- Testing
- Technology Stack
- Advantages Over Other Solutions
- License
Rails Pulse is a comprehensive performance monitoring and debugging gem that provides insights into your Rails application's health. Built as a Rails Engine, it seamlessly integrates with your existing application to capture, analyze, and visualize performance metrics without impacting your production workload.
- Interactive dashboard with response time charts and request analytics
- SQL query performance tracking with slow query identification
- Route-specific metrics with configurable performance thresholds
- Week-over-week trend analysis with visual indicators
- Zero configuration setup with sensible defaults
- Beautiful responsive interface with dark/light mode
- Smart caching with minimal performance overhead
- Multiple database support (SQLite, PostgreSQL, MySQL)
- Flexible tagging system for routes, requests, and queries
- Filter performance data by custom tags
- Organize monitoring data by environment, priority, or custom categories
![]() |
![]() |
Add Rails Pulse to your application's Gemfile:
gem 'rails_pulse'Install the gem:
bundle installGenerate the installation files:
# Install with single database setup (default - recommended)
rails generate rails_pulse:install
# Or install with separate database setup
rails generate rails_pulse:install --database=separateFor single database setup (default):
rails db:migrate # Creates Rails Pulse tables in your main databaseFor separate database setup:
- Configure
config/database.ymlwith your Rails Pulse database settings - Run:
rails db:prepareto create and load the schema
Add the Rails Pulse route to your application:
Rails.application.routes.draw do
mount RailsPulse::Engine => "/rails_pulse"
endSchedule background jobs:
# Schedule to run 5 minutes past every hour. cron: 5 * * * *
RailsPulse::SummaryJob.perform_later
# Schedule to run daily. cron: 0 1 * * *
RailsPulse::CleanupJob.perform_laterRails Pulse automatically starts collecting performance data once installed. Access your monitoring dashboard at:
http://localhost:3000/rails_pulse
Database Setup:
- Single Database (default): Rails Pulse tables are created in your main database - no additional configuration needed
- Separate Database: See the Separate Database Support section for setup instructions
Customize Rails Pulse in config/initializers/rails_pulse.rb:
RailsPulse.configure do |config|
# Enable or disable Rails Pulse
config.enabled = true
# Set performance thresholds for route response times (in milliseconds)
config.route_thresholds = {
slow: 500,
very_slow: 1500,
critical: 3000
}
# Set performance thresholds for request response times (in milliseconds)
config.request_thresholds = {
slow: 700,
very_slow: 2000,
critical: 4000
}
# Set performance thresholds for database queries (in milliseconds)
config.query_thresholds = {
slow: 100,
very_slow: 500,
critical: 1000
}
# Asset tracking configuration
config.track_assets = false # Ignore asset requests by default
config.custom_asset_patterns = [] # Additional asset patterns to ignore
# Rails Pulse mount path (optional)
# Specify if Rails Pulse is mounted at a custom path to prevent self-tracking
config.mount_path = nil # e.g., "/admin/monitoring"
# Route filtering - ignore specific routes from performance tracking
config.ignored_routes = [] # Array of strings or regex patterns
config.ignored_requests = [] # Array of request patterns to ignore
config.ignored_queries = [] # Array of query patterns to ignore
# Tagging system - define available tags for categorizing performance data
config.tags = ["production", "staging", "critical", "needs-optimization"]
# Data cleanup
config.archiving_enabled = true # Enable automatic cleanup
config.full_retention_period = 2.weeks # Delete records older than this
config.max_table_records = { # Maximum records per table
rails_pulse_requests: 10000,
rails_pulse_operations: 50000,
rails_pulse_routes: 1000,
rails_pulse_queries: 500
}
# Multiple database support (optional)
# Uncomment to store Rails Pulse data in a separate database
# config.connects_to = {
# database: { writing: :rails_pulse, reading: :rails_pulse }
# }
endRails Pulse supports flexible authentication to secure access to your monitoring dashboard.
Enable authentication by configuring the following options in your Rails Pulse initializer:
# config/initializers/rails_pulse.rb
RailsPulse.configure do |config|
# Enable authentication
config.authentication_enabled = true
# Where to redirect unauthorized users (optional, defaults to "/")
config.authentication_redirect_path = "/login"
# Define your authentication logic
config.authentication_method = proc {
# Your authentication logic here
}
endRails Pulse works with any authentication system. Here are common patterns:
config.authentication_method = proc {
unless user_signed_in? && current_user.admin?
redirect_to main_app.root_path, alert: "Access denied"
end
}config.authentication_method = proc {
current_user = User.find_by(id: session[:user_id])
unless current_user&.can_access_monitoring?
render plain: "Forbidden", status: :forbidden
end
}Rails Pulse includes a flexible tagging system that allows you to categorize and organize your performance data. Tag routes, requests, and queries with custom labels to better organize and filter your monitoring data.
Define available tags in your Rails Pulse initializer:
RailsPulse.configure do |config|
config.tags = [
"production",
"staging",
"critical",
"needs-optimization",
"high-traffic",
"background-job"
]
endTag from the UI:
- Navigate to any route, request, or query detail page
- Click the "+ tag" button next to the record
- Select from your configured tags
- Remove tags by clicking the × button on any tag badge
Tag Programmatically:
# Tag a route
route = RailsPulse::Route.find_by(path: "/api/users")
route.add_tag("critical")
route.add_tag("high-traffic")
# Tag a query
query = RailsPulse::Query.find_by(normalized_sql: "SELECT * FROM users WHERE id = ?")
query.add_tag("needs-optimization")
# Remove a tag
route.remove_tag("critical")
# Check if has tag
route.has_tag?("production") # => trueUse the global filters modal to filter performance data by tags:
- Click the filter icon in the top navigation
- Select one or more tags from the tag selector
- Apply filters to see only records with those tags
- Tags appear as badges in all data tables for quick visual identification
Common Tagging Strategies:
- By Environment:
production,staging,development - By Priority:
critical,high,medium,low - By Status:
needs-optimization,investigating,resolved - By Type:
api,background-job,user-facing,admin - By Team:
team-frontend,team-backend,team-data
Rails Pulse provides data cleanup to prevent your monitoring database from growing indefinitely while preserving essential performance insights.
Time-based Cleanup
- Automatically delete performance records older than a specified period
- Configurable retention period (default: 2 days)
- Keeps recent data for debugging while removing historical noise
Count-based Cleanup
- Enforce maximum record limits per table
- Prevents any single table from consuming excessive storage
- Configurable limits for each Rails Pulse table
RailsPulse.configure do |config|
# Enable or disable automatic cleanup
config.archiving_enabled = true
# Time-based retention
config.full_retention_period = 2.weeks
# Count-based retention - maximum records per table
config.max_table_records = {
rails_pulse_requests: 10000, # HTTP requests
rails_pulse_operations: 50000, # Operations within requests
rails_pulse_routes: 1000, # Unique routes
rails_pulse_queries: 500 # Normalized SQL queries
}
endRun cleanup manually:
rails rails_pulse:cleanupCheck current database status:
rails rails_pulse:cleanup_statsSchedule automated cleanup:
RailsPulse::CleanupJob.perform_laterRails Pulse offers two database setup options to fit your application's needs:
Stores Rails Pulse data in your main application database alongside your existing tables. This is the simplest setup and works great for most applications.
Advantages:
- Zero additional configuration required
- Simpler backup and deployment strategies
- Works with any database (SQLite, PostgreSQL, MySQL)
Installation:
rails generate rails_pulse:install
rails db:migrateStores Rails Pulse data in a dedicated database, completely isolated from your main application.
Use a separate database when you want:
- Isolating monitoring data from your main application database
- Using different database engines optimized for time-series data
- Scaling monitoring independently from your application
- Simplified backup strategies with separate retention policies
To use a separate database, install with the --database=separate flag, then configure the connects_to option in your Rails Pulse initializer:
RailsPulse.configure do |config|
# Single separate database
config.connects_to = {
database: { writing: :rails_pulse, reading: :rails_pulse }
}
# Or primary/replica configuration
config.connects_to = {
database: { writing: :rails_pulse_primary, reading: :rails_pulse_replica }
}
endAdd the corresponding database configurations to your config/database.yml:
# For SQLite
production:
# ... your main database ...
rails_pulse:
adapter: sqlite3
database: storage/rails_pulse_production.sqlite3
migrations_paths: db/rails_pulse_migrate
pool: 5
timeout: 5000
# For PostgreSQL
production:
# ... your main database ...
rails_pulse:
adapter: postgresql
database: myapp_rails_pulse_production
username: rails_pulse_user
password: <%= Rails.application.credentials.dig(:rails_pulse, :database_password) %>
host: localhost
migrations_paths: db/rails_pulse_migrate
pool: 5
# For MySQL
production:
# ... your main database ...
rails_pulse:
adapter: mysql2
database: myapp_rails_pulse_production
username: rails_pulse_user
password: <%= Rails.application.credentials.dig(:rails_pulse, :database_password) %>
host: localhost
migrations_paths: db/rails_pulse_migrate
pool: 5For separate database setup:
-
Generate installation files:
rails generate rails_pulse:install --database=separate
-
Configure
config/database.yml(see examples above) -
Create and load the schema:
rails db:prepare
This automatically creates the database and loads the Rails Pulse schema.
Schema Management:
The schema file db/rails_pulse_schema.rb serves as your single source of truth for the database structure. It:
- Defines all Rails Pulse tables in one place
- Is loaded by the installation migration
- Should not be deleted or modified
- Future updates will provide migrations in
db/rails_pulse_migrate/
Rails Pulse includes a comprehensive test suite designed for speed and reliability across multiple databases and Rails versions.
# Run all tests (unit, functional, integration, instrumentation)
rails test:all# Unit tests (models, helpers, utilities)
rails test:unit
# Functional tests (controllers, views)
rails test:functional
# Integration tests (end-to-end workflows)
rails test:integration# Run a specific test file
rails test test/models/rails_pulse/request_test.rbTest against multiple databases and Rails versions using the matrix task:
# Test all database and Rails version combinations locally
rails test:matrixThis command tests all combinations locally:
- Databases: SQLite3, PostgreSQL, MySQL2 (local testing only)
- Rails versions: 7.2, 8.0
Note: CI only tests SQLite3 + PostgreSQL for reliability. MySQL is available for local testing but excluded from CI due to flakiness.
-
Copy the environment template:
cp .env.example .env
-
Configure your database credentials in
.env(for local multi-database testing):# PostgreSQL Configuration (used in CI + local) POSTGRES_USERNAME=your_username POSTGRES_PASSWORD=your_password POSTGRES_HOST=localhost POSTGRES_PORT=5432 # MySQL Configuration (local testing only) MYSQL_USERNAME=root MYSQL_PASSWORD=your_password MYSQL_HOST=localhost MYSQL_PORT=3306
-
Create test databases:
# PostgreSQL createdb rails_pulse_test # MySQL mysql -u root -p -e "CREATE DATABASE rails_pulse_test;"
Test individual databases locally:
# Test with SQLite (default)
rails test:all
# Test with PostgreSQL
DB=postgresql FORCE_DB_CONFIG=true rails test:all
# Test with MySQL (local only)
DB=mysql2 FORCE_DB_CONFIG=true rails test:allGitHub Actions CI automatically tests:
- Databases: SQLite3, PostgreSQL only (MySQL excluded for reliability)
- Rails versions: 7.2, 8.0
- Environment: Uses memory SQLite and PostgreSQL service
Local vs CI differences:
- Local: Can test all 3 databases (SQLite3, PostgreSQL, MySQL2)
- CI: Only SQLite3 + PostgreSQL for fast, reliable builds
- Database switching: Requires
FORCE_DB_CONFIG=truelocally
Rails Pulse is built using modern, battle-tested technologies that ensure reliability, performance, and maintainability:
- CSS Zero - Modern utility-first CSS framework bundled for asset independence
- Stimulus - Progressive JavaScript framework for enhanced interactivity
- Turbo - Fast navigation and real-time updates without full page reloads
- Turbo Frames - Lazy loading and partial page updates for optimal performance
- Apache ECharts - Powerful, interactive charting library
- Lucide Icons - Beautiful, consistent iconography with pre-compiled SVG bundle
- Pre-compiled Assets - All CSS, JavaScript, and icons bundled into the gem
- CSP-Safe Implementation - Secure DOM methods and nonce-based asset loading
- Build System - Node.js-based build process for asset compilation
- Zero External Dependencies - Self-contained assets work with any Rails build system
- Request Store - Thread-safe request-scoped storage for performance data
- Rails Caching - Fragment caching with smart invalidation strategies
- ActiveRecord Instrumentation - Built-in Rails performance monitoring hooks
- Rails Generators - Automated installation and configuration
- Omakase Ruby Styling - Consistent code formatting and style
- No External Dependencies: Everything runs in your Rails application with pre-compiled assets
- Zero Monthly Costs: No subscription fees or usage-based pricing
- Data Privacy: All performance data stays in your database(s)
- Customizable: Full control over metrics, thresholds, and interface
- Asset Independence: Works with any Rails build system (Sprockets, esbuild, Webpack, Vite)
- Batteries Included: Complete monitoring solution out of the box
- Proven Architecture: Built on Rails best practices
- Community Driven: Open source with active development
- Professional Design: Production-ready interface
- Rails-Native: Designed specifically for Rails applications
- Developer Experience: Optimized for debugging and development
- Positive Focus: Celebrates good performance alongside problem identification
- Contextual Insights: Deep Rails framework integration for meaningful metrics
- Security First: CSP-compliant by default with secure asset handling
- Zero Build Dependencies: Pre-compiled assets work with any Rails setup
- Flexible Data Storage: Support for multiple database backends (SQLite, PostgreSQL, MySQL)
The gem is available as open source under the terms of the MIT License.


