Separate Dashboard

Deploy Rails Pulse on completely separate infrastructure from your main app — ideal for Kubernetes environments and teams that need full isolation.

When to Use This Pattern

This pattern is the right choice when:

  • You’re running on Kubernetes and want Rails Pulse in its own pod or as a sidecar
  • Your team has compliance or security requirements that mandate infrastructure isolation
  • You want zero possibility of Rails Pulse affecting your main app’s memory, CPU, or connection pool
  • You’re running multiple app instances and don’t want the dashboard to scale with them

If you just want the dashboard to run as a separate process on the same server, see Standalone Dashboard — it’s simpler and may be all you need.

How It Works

Rails Pulse has two distinct roles:

  1. Instrumentation — middleware in your main app that captures requests, queries, and jobs and writes them to the database asynchronously. This is lightweight by design (~0.1ms overhead per request).
  2. Dashboard — a read-only Rack app that serves the Rails Pulse UI and reads from the database.

In the separate instance pattern, these roles run on completely different infrastructure. Your main app handles instrumentation only; the separate instance handles the dashboard.

Main App (instrumentation)
  └── writes metrics → Shared Database ← reads metrics ┐
                                                         Rails Pulse Instance (dashboard)

Configuration Options

The simplest approach. Both your main app and the Rails Pulse instance connect to the same database — they just run on different servers or pods.

Main app — disable the embedded dashboard:

# config/initializers/rails_pulse.rb
RailsPulse.configure do |config|
  config.mount_dashboard = false
end
# config/routes.rb — remove or comment out
# mount RailsPulse::Engine => "/rails_pulse"

Rails Pulse instance — connect to the shared database and start the server:

export DATABASE_URL="postgresql://user:pass@host/myapp_production"
bundle exec rails_pulse_server

Dedicated Rails Pulse Database

For teams that want complete database isolation — no shared connection pool, independent backups, separate credentials.

Add a rails_pulse connection to your main app’s config/database.yml:

production:
  primary:
    adapter: postgresql
    database: myapp_production
    # ... other settings

  rails_pulse:
    adapter: postgresql
    database: myapp_rails_pulse  # Separate database
    migrations_paths: db/rails_pulse_migrate
    # ... other settings

The Rails Pulse instance connects to this dedicated database:

export DATABASE_URL="postgresql://user:pass@host/myapp_rails_pulse"
bundle exec rails_pulse_server

Schema setup: When using a dedicated database, run the Rails Pulse install generator on your main app — it will create the necessary tables in the rails_pulse connection. See Database Setup for details.

Kubernetes Deployment

Sidecar Pattern

Run the Rails Pulse dashboard container in the same pod as your main app. They share the pod’s environment variables and network namespace, making database credentials easy to pass through.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
        - name: app
          image: your-app-image
          # ... main app config

        - name: rails-pulse
          image: your-app-image  # Same image — includes the gem
          command: ["bundle", "exec", "rails_pulse_server"]
          ports:
            - containerPort: 3001
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: database-url
            - name: RAILS_ENV
              value: production
            - name: SECRET_KEY_BASE
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: secret-key-base
          readinessProbe:
            httpGet:
              path: /health
              port: 3001
          livenessProbe:
            httpGet:
              path: /health
              port: 3001

Expose the sidecar via a Service and route to it with an Ingress:

apiVersion: v1
kind: Service
metadata:
  name: rails-pulse
spec:
  selector:
    app: myapp
  ports:
    - port: 3001
      targetPort: 3001

Separate Deployment

For stronger isolation, run Rails Pulse as its own Kubernetes Deployment entirely independent of your main app pods.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: rails-pulse
spec:
  replicas: 1  # Dashboard doesn't need to scale with app instances
  selector:
    matchLabels:
      app: rails-pulse
  template:
    metadata:
      labels:
        app: rails-pulse
    spec:
      containers:
        - name: rails-pulse
          image: your-app-image
          command: ["bundle", "exec", "rails_pulse_server"]
          ports:
            - containerPort: 3001
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: database-url
            - name: RAILS_ENV
              value: production
            - name: SECRET_KEY_BASE
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: secret-key-base
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "256Mi"
              cpu: "250m"
          readinessProbe:
            httpGet:
              path: /health
              port: 3001
          livenessProbe:
            httpGet:
              path: /health
              port: 3001
---
apiVersion: v1
kind: Service
metadata:
  name: rails-pulse
spec:
  selector:
    app: rails-pulse
  ports:
    - port: 3001
      targetPort: 3001
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rails-pulse
spec:
  rules:
    - host: pulse.myapp.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: rails-pulse
                port:
                  number: 3001

Which to choose: Use the sidecar pattern when you want simpler credential sharing and don’t need the dashboard to survive main app pod restarts. Use a separate deployment when the dashboard needs to stay up independently.

Migration Checklist: Embedded → Separate Instance

Zero-downtime migration steps:

  1. Deploy the Rails Pulse instance first (pointing at your existing database) — verify the dashboard works at its new URL before touching the main app
  2. Confirm data is appearing correctly in the new instance
  3. Update main app config — set mount_dashboard = false and remove the engine mount from routes.rb
  4. Deploy the main app changes
  5. Update bookmarks and internal docs with the new dashboard URL
  6. Remove old nginx/load balancer rules pointing to the embedded dashboard path (if any)

Next Steps