PagerDuty is an incident management platform that alerts the right people, coordinates response, and helps teams resolve issues faster. Many engineering teams use it to manage on call rotations and escalations every day.
The PagerDuty plugin brings that context into Backstage. On a service page you can see current incidents, start a new incident, review recent change events, and check who is on call without switching tools. A backend module centralizes calls to the PagerDuty APIs to improve security and performance. The plugin can also sync service dependencies between your Backstage catalog and PagerDuty so relationships stay accurate on both sides. It supports mapping existing PagerDuty services to Backstage entities and creating new services from your software templates.
This helps during an outage because you can confirm impact, page the right responder, and keep work visible in one place. It also helps during onboarding by making PagerDuty setup part of your templates so new services follow the same standards from day one.
Installation Instructions
These instructions apply to self-hosted Backstage only. To use this plugin on Roadie, visit the docs.
Install the packages
-
Add the frontend package to your app
yarn add --cwd packages/app @backstage/plugin-pagerduty
-
Add the backend package to your backend
yarn add --cwd packages/backend @pagerduty/backstage-plugin-backend
Register the frontend API client
-
Open packages/app/src/apis.ts
-
Register the PagerDuty API client
// packages/app/src/apis.ts import { configApiRef, createApiFactory, discoveryApiRef, fetchApiRef, } from '@backstage/core-plugin-api'; import { pagerDutyApiRef, PagerDutyClient, } from '@backstage/plugin-pagerduty'; export const apis = [ // keep existing factories createApiFactory({ api: pagerDutyApiRef, deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef, configApi: configApiRef, }, factory: ({ discoveryApi, fetchApi, configApi }) => PagerDutyClient.fromConfig(configApi, { discoveryApi, fetchApi }), }), ];
Add the PagerDuty card to the Service Entity page
-
Open packages/app/src/components/catalog/EntityPage.tsx
-
Import the card and the entity guard
import { EntityPagerDutyCard, isPagerDutyAvailable, } from '@backstage/plugin-pagerduty'; import { EntitySwitch, } from '@backstage/plugin-catalog-react';
-
Render the card on the Service overview
// inside the Service Entity page route // example layout <EntityLayout> <EntityLayout.Route path="/" title="Overview"> <Grid container spacing={3} alignItems="stretch"> <Grid item xs={12} md={6}> <EntitySwitch> <EntitySwitch.Case if={isPagerDutyAvailable}> <EntityPagerDutyCard /> {/* Optional props <EntityPagerDutyCard readOnly /> <EntityPagerDutyCard disableChangeEvents /> */} </EntitySwitch.Case> </EntitySwitch> </Grid> </Grid> </EntityLayout.Route> </EntityLayout>
Add the PagerDuty card to the Home page optional
-
Open packages/app/src/components/home/HomePage.tsx
-
Import the card
import { HomePagePagerDutyCard } from '@backstage/plugin-pagerduty';
-
Render it on the page
<Grid container spacing={3}> <Grid item xs={12} md={6}> <HomePagePagerDutyCard // Provide either integrationKey or serviceId plus a name // Example using serviceId name="Payments Service" serviceId="P123456" // Optional readOnly // readOnly /> </Grid> </Grid>
Add a Trigger Incident button optional
-
Import the button
import { TriggerButton } from '@backstage/plugin-pagerduty';
-
Place it where it fits your UI
<TriggerButton> Create PagerDuty incident </TriggerButton>
Configure entity annotations
-
Add one of these annotations to each Service entity yaml
Using service id
metadata: annotations: pagerduty.com/service-id: P123456
Using integration key
metadata: annotations: pagerduty.com/integration-key: abcdef0123456789
If both are present the integration key takes precedence
Set secrets for the backend
- Set these environment variables in the backend process
export PAGERDUTY_CLIENT_ID=your_oauth_client_id export PAGERDUTY_CLIENT_SECRET=your_oauth_client_secret export PAGERDUTY_SUBDOMAIN=your_pd_subdomain
Wire the backend on the classic backend system
-
Create a router factory
// packages/backend/src/plugins/pagerduty.ts import { Logger } from 'winston'; import { PluginEnvironment } from '../types'; import { createRouter } from '@pagerduty/backstage-plugin-backend'; export default async function createPlugin( env: PluginEnvironment, ) { return await createRouter({ logger: env.logger as Logger, config: env.config, discovery: env.discovery, tokenManager: env.tokenManager, }); }
-
Mount the router in the backend index
// packages/backend/src/index.ts import { createServiceBuilder } from '@backstage/backend-common'; import { useHotMemoize } from '@backstage/backend-common'; import { createEnv } from './lib/createEnv'; async function main() { const env = await createEnv('backend'); const apiRouter = Router(); const pagerdutyEnv = useHotMemoize(module, () => createEnv('pagerduty')); const pagerdutyRouter = await require('./plugins/pagerduty').default(pagerdutyEnv); apiRouter.use('/pagerduty', await pagerdutyRouter); const service = createServiceBuilder(module) .setPort(env.backend.port) .addRouter('/api', apiRouter); await service.start(); } main().catch(err => { process.exit(1); });
The router mounts at path
api/pagerduty
Wire the backend on the new backend system
-
Mount the same router using the new backend APIs
// packages/backend/src/index.ts import { createBackend } from '@backstage/backend-defaults'; import { coreServices, createBackendPlugin, } from '@backstage/backend-plugin-api'; import { createRouter as createPagerDutyRouter } from '@pagerduty/backstage-plugin-backend'; const backend = createBackend(); backend.add( createBackendPlugin({ pluginId: 'pagerduty', register(env) { env.registerInit({ deps: { httpRouter: coreServices.httpRouter, logger: coreServices.logger, config: coreServices.rootConfig, discovery: coreServices.discovery, tokenManager: coreServices.tokenManager, }, async init({ httpRouter, logger, config, discovery, tokenManager, }) { const router = await createPagerDutyRouter({ logger, config, discovery, tokenManager, }); httpRouter.use('/pagerduty', router); }, }); }, }), ); backend.start();
The router mounts at path
api/pagerduty
Run the app
-
Start the backend in one terminal
yarn start-backend
-
Start the frontend in another terminal
yarn start
Things to Know
The PagerDuty plugin is a frontend plugin that provides convenient access to frequently used PagerDuty capabilities. Developers see pertinent information and actions for every entity that is connected to a PagerDuty service including:
- who is currently on call for the entity
- whether there are any active incidents for the entity
- raise a new incident for the entity
Connecting an entity to a PagerDuty service
An entity is connected to a PagerDuty service by adding a pagerduty.com/integration-key
annotation to the entity’s catalog-info.yaml
file. For example:
annotations:
pagerduty.com/integration-key: a8642af33a984c07d01144f420df074e
The integration key can be retrieved from the Integrations tab of the service in the PagerDuty service directory.
PagerDuty UI placement and rendering
In the example above, the PagerDuty UI was added to the Overview tab for all entities. The PagerDuty panel was conditionally rendered only for entities that are actual connected to a PagerDuty service using the isPagerDutyAvailable
function.
You are not constrained to displaying the PagerDuty panel on the Overview tab. Where and how you display the PagerDuty panel is completely within your control. For example, what if your organization has a policy that requires all APIs to have on call support? Rather than hiding the PagerDuty panel when an API entity is not connected to a PagerDuty service, you could display a policy reminder. Not only can Backstage provide access to frequently used PagerDuty capabilities but it can also help bring visibility to policy gaps.
Changelog
This changelog is produced from commits made to the PagerDuty plugin since 3 months ago, and based on the code located here. It may not contain information about all commits. Releases and version bumps are intentionally omitted. This changelog is generated by AI.
Set up Backstage in minutes with Roadie
Focus on using Backstage, rather than building and maintaining it.