Deployment Modes
Rails Pulse can run embedded in your app, as a standalone dashboard process, or split across separate infrastructure. Choose the mode that fits your setup.
Rails Pulse has two distinct jobs: instrumentation (collecting and writing metrics) and the dashboard (reading and displaying them). These can run together or be separated depending on your needs.
The three modes
1. Embedded (default)
The dashboard runs inside your main Rails app. Mount the engine and everything works out of the box.
# config/routes.rb
mount RailsPulse::Engine, at: "/rails_pulse"
Instrumentation and the dashboard share your app’s process, connection pool, and lifecycle. If your app is down, so is the dashboard.
Best for: Development, low-traffic apps, getting started.
2. Standalone dashboard process
The dashboard runs as a separate process on the same server, started with rails_pulse_server. Your main app continues to handle instrumentation and writes metrics to the database — the standalone process just reads from that same database.
bundle exec rails_pulse_server # starts on port 3001
The dashboard stays up even when your main app is restarting or under load. It has its own port, its own session middleware, and a /health endpoint for load balancers.
Best for: Production apps on a single server, Kamal deployments, keeping the dashboard available during deploys.
3. Separate instance
Your main app runs instrumentation only (mount_dashboard: false). A completely separate server or pod — on different infrastructure — runs rails_pulse_server and serves the dashboard.
# Main app — instrumentation only
RailsPulse.configure do |config|
config.mount_dashboard = false
end
Both connect to the same database, or you can give Rails Pulse its own dedicated database entirely.
Best for: Kubernetes, compliance requirements, zero resource contention between monitoring and application traffic.
Comparison
| Embedded | Standalone | Separate instance | |
|---|---|---|---|
| How it starts | Part of your Rails app | rails_pulse_server | rails_pulse_server on separate infra |
| Instrumentation | Yes | No | Yes (main app only) |
| Dashboard UI | Yes | Yes | No (main app) / Yes (separate server) |
| Process count | 1 | 2 | 2 |
mount_dashboard | true | N/A | false on main app |
config.enabled | true | false | true on main app, false on dashboard server |
| Database | Main app’s DB | Same DB as main app | Shared or dedicated DB |
| Health endpoint | No | Yes (/health) | Yes (/health) |
| Resource isolation | None | Dashboard isolated | Full isolation |
| Dashboard survives app restart | No | Yes | Yes |
How data flows in every mode
Regardless of which mode you choose, the data pipeline is identical on the collection side:
OperationSubscriberhooks intoActiveSupport::Notificationsand accumulates per-operation data (SQL queries, template renders, cache reads, etc.) intoRequestStoreduring the requestRequestCollectormiddleware grabs everything fromRequestStoreafter the response is builtTrackerfires anAsync { }fiber to writeRoute,Request, andOperationrecords to the database
The database is the only communication channel between the main app and a standalone/separate dashboard process — there’s no API, no message queue, no pub/sub.