Skip to content

feat(grafana): add support for multiple Grafana instances#7527

Open
andreahlert wants to merge 11 commits intobackstage:mainfrom
andreahlert:feat/grafana-multiple-instances
Open

feat(grafana): add support for multiple Grafana instances#7527
andreahlert wants to merge 11 commits intobackstage:mainfrom
andreahlert:feat/grafana-multiple-instances

Conversation

@andreahlert
Copy link
Contributor

Summary

Closes #1293

Adds the ability to configure multiple Grafana instances, allowing organizations with separate Grafana deployments (e.g., production and staging) to use them all within Backstage.

  • New grafana.hosts[] configuration with per-host domain, proxyPath, unifiedAlerting, and search settings
  • New grafana/source-id entity annotation to associate entities with specific Grafana instances
  • Merged API client to handle unified and legacy alerting per-host (not globally)
  • Full backward compatibility with existing single-instance grafana.domain configuration
  • Proxy path collision detection to prevent silent misconfiguration

Changes

Core:

  • config.d.ts - Added hosts[] config schema
  • src/types.ts - Added GrafanaHost interface
  • src/constants.ts - Added GRAFANA_ANNOTATION_SOURCE_ID and sourceIdFromEntity()
  • src/api.ts - Merged two API client classes into one multi-host client with isUnifiedAlerting() per-host resolution
  • src/config.ts - Shared readHosts() utility with validation
  • src/plugin.ts / src/alpha/apis.ts - Updated factories using shared config

Components:

  • AlertsCard.tsx - Uses per-host isUnifiedAlerting() instead of global config
  • DashboardsCard.tsx - Passes sourceId to API calls

Tests (+24 new tests):

  • api.test.ts - Host resolution, isUnifiedAlerting per-host, fallback, error cases
  • config.test.ts - Config reading, validation, proxy path collision
  • constants.test.ts - sourceIdFromEntity with/without annotation
  • AlertsCard.test.tsx - Integration tests for per-host unified alerting selector flow

Docs:

  • setup.md - Multi-instance configuration guide
  • alerts-on-component-page.md / dashboards-on-component-page.md - grafana/source-id usage

Configuration example

proxy:
  '/grafana/production/api':
    target: https://grafana-prod.host/
    headers:
      Authorization: Bearer ${GRAFANA_PROD_TOKEN}
  '/grafana/staging/api':
    target: https://grafana-staging.host/
    headers:
      Authorization: Bearer ${GRAFANA_STAGING_TOKEN}

grafana:
  hosts:
    - id: production
      domain: https://monitoring-prod.company.com
      proxyPath: /grafana/production/api
      unifiedAlerting: true
    - id: staging
      domain: https://monitoring-staging.company.com
      proxyPath: /grafana/staging/api
      unifiedAlerting: false
# catalog-info.yaml
metadata:
  annotations:
    grafana/source-id: production
    grafana/dashboard-selector: my-service
    grafana/alert-label-selector: service=my-service

Test plan

  • All existing tests pass (8 suites, 37 tests)
  • TypeScript compilation passes
  • Lint passes
  • API reports regenerated without warnings
  • Build succeeds
  • Verify single-instance config still works (backward compat)
  • Verify multi-instance config routes to correct Grafana instances
  • Verify entity without grafana/source-id falls back to default host

@andreahlert andreahlert requested a review from a team as a code owner February 8, 2026 09:08
@andreahlert andreahlert requested review from vinzscam and removed request for a team February 8, 2026 09:08
@backstage-goalie
Copy link
Contributor

backstage-goalie bot commented Feb 8, 2026

Changed Packages

Package Name Package Path Changeset Bump Current Version
@backstage-community/plugin-grafana workspaces/grafana/plugins/grafana minor v0.15.0

@backstage-goalie
Copy link
Contributor

Thanks for the contribution!
All commits need to be DCO signed before they are reviewed. Please refer to the the DCO section in CONTRIBUTING.md or the DCO status for more info.

Add the ability to configure multiple Grafana instances under a
`grafana.hosts` config key. Each host can have its own domain,
proxy path, and alerting mode. Entities are associated with a
specific instance via the `grafana/source-id` annotation.

Key changes:
- New `grafana.hosts[]` config schema with per-host settings
- New `grafana/source-id` entity annotation
- Merged GrafanaApiClient to handle both unified and legacy
  alerting per-host instead of globally
- AlertsCard resolves unifiedAlerting per-host, not from global config
- Shared readHosts() config utility with proxy path validation
- Full backward compatibility with single-instance `grafana.domain`

Signed-off-by: André Ahlert <andre@aex.partners>
@andreahlert andreahlert force-pushed the feat/grafana-multiple-instances branch from 388de1b to 4eb589f Compare February 8, 2026 09:14
@andreahlert
Copy link
Contributor Author

Hey @awanlin, this implements the multiple Grafana instances support from #1293.

I based the approach on K-Phoen/backstage-plugin-grafana#76 but adapted it to the current codebase, with some improvements: per-host unifiedAlerting resolution (the original had a bug where AlertsCard used the global config), proxy path collision detection, and test coverage for the multi-instance flow.

I've been actively contributing to community-plugins lately - created the n8n workspace (#7522), submitted a few fixes for sentry (#7523, #7525, #7526), and now this. I've been focusing on workspaces that could use some extra attention, and I'd be happy to help maintain this one going forward.

@andreahlert
Copy link
Contributor Author

Hi @awanlin, this PR implements multi-instance Grafana support as requested in #1293. I've kept full backward compatibility with the existing single-instance config while adding the new grafana.hosts[] array.

I've also opened #7528 adding unit test coverage for the API clients (GrafanaApiClient and UnifiedAlertingGrafanaApiClient), which previously had none.

Would you be able to review or suggest another reviewer? Happy to address any feedback.

@awanlin
Copy link
Contributor

awanlin commented Feb 8, 2026

Hi @andreahlert, while we appreciate contributions, let's hold off on conversations regarding ownership changes.

I'd also suggest reading our Contributing guide as that covers the review process: https://github.com/backstage/community-plugins/blob/main/CONTRIBUTING.md#review-process. I'd also suggest you read over the AI Policy in the upstream Backstage repo as that very much applies here as well: https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#ai-use-policy-and-guidelines.

This repo is volunteer run, reviews will be slow as they are based on Plugin Owner availability. Traditionally I only have time for them on Friday afternoons. I just happen to be doing some work and spotted your PRs yesterday and wanted to help set you on the right footing as they had some good and not good aspects to them. Today I'm just following up as I was ping multiple times and wanted to know why. 👍

@andreahlert
Copy link
Contributor Author

Hi @andreahlert, while we appreciate contributions, let's hold off on conversations regarding ownership changes.

I'd also suggest reading our Contributing guide as that covers the review process: https://github.com/backstage/community-plugins/blob/main/CONTRIBUTING.md#review-process. I'd also suggest you read over the AI Policy in the upstream Backstage repo as that very much applies here as well: https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#ai-use-policy-and-guidelines.

This repo is volunteer run, reviews will be slow as they are based on Plugin Owner availability. Traditionally I only have time for them on Friday afternoons. I just happen to be doing some work and spotted your PRs yesterday and wanted to help set you on the right footing as they had some good and not good aspects to them. Today I'm just following up as I was ping multiple times and wanted to know why. 👍

Hey @awanlin, noted on all points.

About the AI policy and Contributing Guide: I went through it, I take code quality seriously and like to keep things well documented, which might come across as over-structured sometimes.

I wasn't trying to push for ownership either, just wanted to show I'm around and interested in helping out.

And yeah, the multiple pings that's an annoying habit of mine, sorry about that 😅. I promise I'll behave, I don't want to be that guy who makes you regret checking GitHub on a Saturday. I set aside one day a week for Backstage stuff but got a bit carried away and spent some extra hours because I was enjoying the work.

I contribute to other repos too so I get how volunteer time works, so no rush on the review. Thanks for taking the time to point me in the right direction.

Copy link
Member

@vinzscam vinzscam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you!

@andreahlert andreahlert force-pushed the feat/grafana-multiple-instances branch from 2dee0ac to 750a182 Compare February 11, 2026 21:27
grafana/alert-label-selector: service=my-service
```

If the `grafana/host-id` annotation is not set, the plugin will use the first configured host (or the `default` host created from the legacy `domain` config).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before this gets baked in, can we please have an option that controls the default, rather than just taking the "first configured host"? I foresee orgs that have large catalogs without the new annotation will have to take time to migrate, and the subtle behavior of "first is default" seems like it will cause future problems.

Prefer something like:

grafana:
  defaultHost: production
  hosts:
    - id: production
      domain: https://monitoring-prod.company.com
      proxyPath: /grafana/production/api
      unifiedAlerting: true

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct me if I'm wrong @robbat2, but those orgs that don't migrate they will only have a single instance, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct - if they don't migrate, they will have a single instance.
What I want is an easier time for the orgs that DO want to migrate. Having the first entry of hosts be silently special for the migration feels too much automatic magic, vs explicitly declaring which host is the default for catalog entities that don't have the host-id declared.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented grafana.defaultHost so you can explicitly set which host is used when the entity has no grafana/host-id. Setup doc updated accordingly. WDYT @robbat2 and @vinzscam?

@andreahlert andreahlert force-pushed the feat/grafana-multiple-instances branch 3 times, most recently from b86856b to 4f88f27 Compare February 23, 2026 07:20
@andreahlert andreahlert force-pushed the feat/grafana-multiple-instances branch from f33b999 to 261ff2b Compare February 23, 2026 08:10
andreahlert and others added 8 commits February 23, 2026 07:02
- Remove custom GrafanaConfigApi interface, use ConfigApi from @backstage/core-plugin-api

- When both grafana.domain and grafana.hosts are set, ignore domain and log warning

- Remove @public from GrafanaApiClient class

- Rename grafana/source-id to grafana/host-id annotation

- Remove per-host grafanaDashboardSearchLimit/grafanaDashboardMaxPages, keep global only

- Mark global grafanaDashboardSearchLimit/grafanaDashboardMaxPages as @deprecated

Signed-off-by: André Ahlert <andre@aex.partners>
Co-authored-by: Vincenzo Scamporlino <vincenzos@spotify.com>
Signed-off-by: André Ahlert <andre@aex.partners>
Signed-off-by: André Ahlert <andre@aex.partners>
Signed-off-by: André Ahlert <andre@aex.partners>
Add eslint-disable comments for intentional use of deprecated config keys
(grafana.domain, grafana.proxyPath, grafana.unifiedAlerting,
grafanaDashboardSearchLimit, grafanaDashboardMaxPages) so CI list-deprecations
check passes while keeping backward compatibility.

- Fix indent of eslint-enable in config.ts
- Use dashboardSearchLimit/dashboardMaxPages in GrafanaApiClientOptions
  to match plugin.ts and apis.ts (fix type checking).

Signed-off-by: André Ahlert <andre@aex.partners>
Add defaultHostId to GrafanaApiClientOptions in report.api.md so
check api reports and generate API reference CI step passes.

Signed-off-by: André Ahlert <andre@aex.partners>
- Regenerated report.api.md and report-alpha.api.md using backstage-repo-tools\n- Includes the new defaultHostId property in GrafanaApiClientOptions\n- Fixes CI validation failure on 'check api reports and generate API reference'

Signed-off-by: André Ahlert <andre@aex.partners>
Regenerate report.api.md and report-alpha.api.md to match the current API Extractor output used in CI, fixing the build:api-reports:only --ci failure on PR 7527.

Signed-off-by: André Ahlert <andre@aex.partners>
@andreahlert andreahlert force-pushed the feat/grafana-multiple-instances branch from d0fbce8 to 065ecc9 Compare February 23, 2026 10:03
Update EntityGrafanaAlertsCard and EntityGrafanaDashboardsCard signatures in report.api.md to match API Extractor output from CI (Node 22/24), resolving the remaining api report mismatch.

Signed-off-by: André Ahlert <andre@aex.partners>
Update report-alpha.api.md from API Extractor output generated under Node 22/24 to match CI expectations and fix build:api-reports:only --ci failures.

Signed-off-by: André Ahlert <andre@aex.partners>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🚀 Grafana: Support to multiple instances

5 participants