CubeAPM
CubeAPM CubeAPM

How to Monitor Backstage (IDP) Performance and Plugin Health: Step by Step Guide 2026

How to Monitor Backstage (IDP) Performance and Plugin Health: Step by Step Guide 2026

Table of Contents

Backstage is an open source framework for building internal developer portals (IDPs), but once deployed, most teams struggle to answer basic operational questions: which plugins are failing, which backend processes are slow, and whether the catalog refresh pipeline is actually working. According to the CNCF 2024 Annual Survey, 43% of organizations using internal developer portals reported performance issues as the primary barrier to adoption.

This guide shows how to instrument Backstage with metrics, logs, and health checks so you can track plugin latency, catalog sync failures, and backend response times in production. You will learn how to surface plugin specific metrics, set up alerts for catalog staleness, and connect Backstage observability to your broader infrastructure monitoring stack.

Prerequisites

Before starting, ensure you have:

  • Backstage deployed and running (v1.20 or later recommended)
  • Access to backend configuration files (app-config.yaml)
  • Prometheus installed or access to a Prometheus compatible metrics endpoint
  • Basic familiarity with Backstage plugins and the catalog refresh process
  • Admin access to modify Backstage backend startup scripts
  • Optional: Grafana or equivalent dashboard tool for visualization

Step 1: Enable Backstage Backend Metrics Endpoint

Backstage exposes a Prometheus metrics endpoint at /.backstage/metrics by default, but you need to verify it is enabled and accessible.

Check if the metrics endpoint is responding:

curl http://localhost:7007/.backstage/metrics

If the endpoint returns a 404 or connection refused, enable it explicitly in app-config.yaml:

backend:
  baseUrl: http://localhost:7007
  listen:
    port: 7007
  metrics:
    enabled: true

Restart your Backstage backend:

yarn workspace backend start

Verify the endpoint again. You should see output similar to:

# HELP backstage_http_requests_total Total number of HTTP requests
# TYPE backstage_http_requests_total counter
backstage_http_requests_total{method="GET",path="/catalog",status="200"} 1523

This confirms that Backstage is now exporting metrics in Prometheus format. The default metrics include HTTP request counts, latency histograms, and catalog entity counts.

Step 2: Configure Prometheus to Scrape Backstage Metrics

Add a scrape job in your Prometheus configuration to collect Backstage metrics every 15 seconds.

Edit prometheus.yml:

scrape_configs:
  - job_name: 'backstage'
    scrape_interval: 15s
    static_configs:
      - targets: ['localhost:7007']
    metrics_path: /.backstage/metrics

Reload Prometheus:

curl -X POST http://localhost:9090/-/reload

Verify the target is up in the Prometheus UI at http://localhost:9090/targets. The Backstage target should show state UP with the last scrape time visible.

Query a basic metric to confirm data is flowing:

rate(backstage_http_requests_total[5m])

If this returns results, Prometheus is successfully collecting Backstage metrics.

Step 3: Track Catalog Refresh Performance and Failures

Backstage’s catalog refresh process runs in the background to sync entities from external sources like GitHub, GitLab, or static YAML files. Staleness or failures here break the entire IDP experience.

Monitor catalog refresh duration using the backstage_catalog_processing_duration_seconds histogram. This metric tracks how long each catalog location takes to process.

Query catalog refresh latency:

histogram_quantile(0.95, rate(backstage_catalog_processing_duration_seconds_bucket[5m]))

This returns the 95th percentile refresh latency. If this number climbs above 30 seconds consistently, catalog refresh is degrading.

Track catalog refresh failures with backstage_catalog_processing_errors_total:

rate(backstage_catalog_processing_errors_total[5m])

A non zero rate here means catalog locations are failing to sync. Check Backstage backend logs for the specific error messages.

Set an alert in Prometheus or Alertmanager when catalog refresh errors spike:

groups:
  - name: backstage_catalog
    rules:
      - alert: CatalogRefreshFailures
        expr: rate(backstage_catalog_processing_errors_total[5m]) > 0.1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Backstage catalog refresh failing"
          description: "Catalog location sync errors detected at {{ $value }} per second"

This alert fires if catalog refresh errors exceed 0.1 per second sustained over 5 minutes.

Step 4: Monitor Plugin Specific Backend Latency

Backstage plugins expose their own backend routes under /api/{plugin-id}. You need plugin level latency metrics to isolate slow plugins.

Query HTTP request latency grouped by path:

histogram_quantile(0.95, 
  rate(backstage_http_request_duration_seconds_bucket{path=~"/api/.*"}[5m])
)

This shows the 95th percentile latency for all plugin API routes. Identify slow plugins by filtering:

histogram_quantile(0.95, 
  rate(backstage_http_request_duration_seconds_bucket{path=~"/api/catalog/.*"}[5m])
)

Replace /api/catalog/ with the specific plugin route you are investigating. Common plugin paths include:

  • /api/catalog — Catalog backend
  • /api/scaffolder — Scaffolder backend
  • /api/techdocs — TechDocs backend
  • /api/kubernetes — Kubernetes plugin backend
  • /api/search — Search backend

If a specific plugin consistently shows latency above 2 seconds, investigate its configuration, external API dependencies, or database queries.

Step 5: Set Up Health Checks for Critical Backstage Services

Backstage provides readiness and liveness endpoints at /.backstage/health/v1/readiness and /.backstage/health/v1/liveness starting from version 1.29.0.

Check readiness:

curl http://localhost:7007/.backstage/health/v1/readiness

Expected response:

{"status": "ok"}

Check liveness:

curl http://localhost:7007/.backstage/health/v1/liveness

These endpoints return HTTP 200 if the backend is healthy, or HTTP 503 if a critical dependency like the database is unreachable.

Configure Kubernetes liveness and readiness probes if running Backstage in Kubernetes:

livenessProbe:
  httpGet:
    path: /.backstage/health/v1/liveness
    port: 7007
  initialDelaySeconds: 30
  periodSeconds: 10
readinessProbe:
  httpGet:
    path: /.backstage/health/v1/readiness
    port: 7007
  initialDelaySeconds: 10
  periodSeconds: 5

This ensures Kubernetes restarts unhealthy Backstage pods automatically.

Step 6: Monitor Frontend Performance with Real User Monitoring

Backstage frontend performance affects developer experience directly. Slow page loads or unresponsive UI hurts adoption.

If you use Real User Monitoring (RUM) in your observability stack, instrument the Backstage frontend to track:

  • Page load time for catalog pages
  • Time to interactive for software templates
  • JavaScript errors in plugins
  • API call latency from frontend to backend

For Datadog RUM, add the RUM SDK to packages/app/src/App.tsx:

import { datadogRum } from '@datadog/browser-rum';

datadogRum.init({
  applicationId: 'your-app-id',
  clientToken: 'your-client-token',
  site: 'datadoghq.com',
  service: 'backstage',
  env: 'production',
  version: '1.0.0',
  sessionSampleRate: 100,
  sessionReplaySampleRate: 20,
  trackUserInteractions: true,
  trackResources: true,
  trackLongTasks: true,
});

This captures frontend performance data and correlates it with backend traces if APM is configured.

If you are using CubeAPM, integrate RUM by adding the CubeAPM browser SDK to the Backstage frontend, which tracks page load times, user interactions, and JavaScript errors without requiring a separate RUM product. CubeAPM correlates frontend RUM data with backend APM traces automatically.

Step 7: Set Up Alerts for Backstage Performance Degradation

Define alerting rules for critical Backstage reliability signals. These should fire before users notice problems.

Example Alertmanager rules:

groups:
  - name: backstage_alerts
    rules:
      - alert: BackstageHighLatency
        expr: histogram_quantile(0.95, rate(backstage_http_request_duration_seconds_bucket[5m])) > 2
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Backstage API latency above 2s"
          description: "95th percentile latency is {{ $value }}s"

      - alert: BackstageCatalogStale
        expr: time() - backstage_catalog_last_refresh_timestamp_seconds > 3600
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Backstage catalog refresh stale"
          description: "Catalog has not refreshed in over 1 hour"

      - alert: BackstagePluginErrors
        expr: rate(backstage_http_requests_total{status=~"5.."}[5m]) > 0.05
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Backstage plugin returning 5xx errors"
          description: "Error rate is {{ $value }} per second"

Route these alerts to Slack, PagerDuty, or email depending on severity.

Step 8: Build Dashboards to Visualize Backstage Health

Create Grafana dashboards to track Backstage performance over time. Use the following panels as a starting point.

Panel 1: HTTP Request Rate

sum(rate(backstage_http_requests_total[5m])) by (method, path)

Panel 2: Catalog Entity Count

backstage_catalog_entities_count

Panel 3: Plugin Latency Heatmap

histogram_quantile(0.95, rate(backstage_http_request_duration_seconds_bucket{path=~"/api/.*"}[5m]))

Panel 4: Catalog Refresh Errors

rate(backstage_catalog_processing_errors_total[5m])

Panel 5: Backend Memory Usage

process_resident_memory_bytes{job="backstage"}

These panels give you a single pane view of Backstage health. If you integrate with CubeAPM, all of these metrics and logs are unified in one platform with automatic correlation between frontend RUM, backend APM, and infrastructure metrics.

Troubleshooting Common Issues

Metrics endpoint returns 404

Verify backend.metrics.enabled: true in app-config.yaml and restart the backend. Check that port 7007 is not blocked by firewall rules.

Catalog refresh takes longer than 60 seconds

Check the number of catalog locations in app-config.yaml. Each location is processed sequentially. Split large monorepos into smaller catalog locations or increase backend memory allocation.

High memory usage in Backstage backend

Backstage backend memory usage grows with entity count. Monitor process_resident_memory_bytes and scale vertically or horizontally if usage exceeds 2 GB sustained. Consider enabling catalog incremental refresh if available in your Backstage version.

Plugins return intermittent 503 errors

This often indicates database connection pool exhaustion. Increase backend.database.connection.max in app-config.yaml and monitor active database connections.

Frontend pages load slowly but backend metrics look fine

Check browser network tab for slow asset loading. Verify CDN caching is enabled for static assets. Profile JavaScript execution time in browser developer tools. Consider enabling code splitting in the Backstage frontend build.

Once you have established baseline Backstage observability using Prometheus, logs, and health checks, the next operational challenge is unifying this data with your broader observability stack. Most teams run Backstage alongside dozens of other services, and isolating Backstage issues from upstream dependencies like GitHub API rate limits, database slowness, or Kubernetes scheduler delays requires correlated telemetry across the entire stack. Tools like frontend performance monitoring platforms help connect user facing latency to backend service health, while database specific monitoring like Cassandra monitoring tools can surface query bottlenecks that degrade catalog refresh performance. The goal is to ensure that when Backstage slows down or fails, you can trace the root cause across every layer of your infrastructure without switching between disconnected tools.

Frequently Asked Questions

How do I monitor Backstage plugin health individually?

Use the `backstage_http_request_duration_seconds` metric filtered by `path` label to isolate latency per plugin route. Each plugin backend exposes routes under `/api/{plugin-id}`, making per plugin monitoring straightforward.

What metrics indicate Backstage catalog is unhealthy?

Monitor `backstage_catalog_processing_errors_total` for sync failures and `backstage_catalog_last_refresh_timestamp_seconds` for staleness. If refresh timestamp stops advancing or error rate spikes, catalog sync is broken.

Can I monitor Backstage with Datadog or New Relic?

Yes, both tools can scrape the Prometheus metrics endpoint at `/.backstage/metrics`. Configure a Prometheus integration in Datadog or use the New Relic Prometheus exporter to ingest Backstage metrics.

How do I track plugin installation failures?

Backstage does not expose plugin installation metrics by default. Monitor backend startup logs for plugin initialization errors and set up log based alerts for patterns like “Failed to initialize plugin” or “Plugin dependency missing”.

What is the recommended alert threshold for catalog refresh latency?

Set a warning alert at 30 seconds and a critical alert at 60 seconds for 95th percentile catalog refresh duration. Adjust based on your catalog size and external API latency.

How do I monitor Backstage in Kubernetes?

Use the liveness and readiness probes at `/.backstage/health/v1/liveness` and `/.backstage/health/v1/readiness`. Combine with Prometheus scraping of the metrics endpoint and correlate with Kubernetes events using a Kubernetes monitoring tool.

Can I use OpenTelemetry with Backstage?

Backstage does not ship with native OpenTelemetry instrumentation as of version 1.30. You can add OpenTelemetry tracing manually by instrumenting the backend with the Node.js OpenTelemetry SDK, but this requires custom code changes.

Disclaimer: The information in this article reflects the latest details available at the time of publication and may change as technologies and products evolve. Features, pricing, and plan limits can change over time. Always verify the latest information directly with the vendor before making purchasing or deployment decisions.

×
×