DX gives you a clear view of software delivery and developer experience. The DX Backstage plugin brings that data into your self hosted portal so teams can see what matters where they already work.
The plugin surfaces scorecards and tasks for each service. You can show current levels and check results for your teams, plus a page that lists open tasks by priority. It can also render custom charts and tables backed by DX Data Cloud queries. Many teams use it to track DORA metrics like deployment frequency, change failure rate, time to recovery, and lead time. You decide what to show on each entity page so the signal stays focused.
DX is listed in the Backstage marketplace. The description highlights DORA metrics, developer experience scores, and service insights inside Backstage.
Installation Instructions
These instructions apply to self-hosted Backstage only.
Install the frontend package
yarn --cwd packages/app add @get-dx/backstage-plugin
Configure the DX API proxy
Create a DX Web API token that includes the catalog read scope. Put the token in your Backstage config. This uses the proxy so the frontend does not call the DX API directly.
# app-config.yaml
proxy:
endpoints:
"/dx-web-api":
target: https://api.getdx.com
headers:
Authorization: Bearer ${DX_WEB_API_TOKEN}
allowedHeaders:
- X-Client-Type
- X-Client-Version
Set the DX_WEB_API_TOKEN environment variable in your runtime environment.
Enable the proxy in your Backstage backend
Your backend must expose the proxy for the app config shown above. Use one of these setups.
New backend
Install the backend proxy plugin
yarn --cwd packages/backend add @backstage/plugin-proxy-backend
Register it in the backend entry file
// packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';
import { proxyPlugin } from '@backstage/plugin-proxy-backend';
const backend = createBackend();
backend.add(proxyPlugin());
backend.start();
Legacy backend
Install the backend proxy plugin
yarn --cwd packages/backend add @backstage/plugin-proxy-backend
Create a proxy plugin module
// packages/backend/src/plugins/proxy.ts
import { createRouter } from '@backstage/plugin-proxy';
import { PluginEnvironment } from '../types';
export default async function createPlugin(env: PluginEnvironment) {
return await createRouter({
logger: env.logger,
config: env.config,
});
}
Wire it in the backend router
// packages/backend/src/index.ts
import proxy from './plugins/proxy';
// inside the main bootstrap function
const proxyEnv = useHotMemoize(module, () => createEnv('proxy'));
apiRouter.use('/proxy', await proxy(proxyEnv));
Register the DX plugin in your app
Add the DX plugin to your app so wrapper components work as expected.
// packages/app/src/App.tsx
import { createApp } from '@backstage/app-defaults';
import { dxPlugin } from '@get-dx/backstage-plugin';
const app = createApp({
// other options
plugins: [dxPlugin],
});
export default app.createRoot();
Add full page routes on the service entity page
Add the scorecards and tasks pages. Use your DX entity identifier in the props. You can hardcode a value to start, then switch to a wrapper as shown later.
// packages/app/src/components/catalog/EntityPage.tsx
import React from 'react';
import { EntityLayout } from '@backstage/plugin-catalog';
import { EntityScorecardsPage, EntityTasksPage } from '@get-dx/backstage-plugin';
const serviceEntityPage = (
<EntityLayout>
{/* other routes */}
<EntityLayout.Route path="/dx-scorecards" title="Scorecards">
<EntityScorecardsPage entityIdentifier="my-app" />
</EntityLayout.Route>
<EntityLayout.Route path="/dx-tasks" title="Tasks">
<EntityTasksPage entityIdentifier="my-app" />
</EntityLayout.Route>
</EntityLayout>
);
export default serviceEntityPage;
Show scorecards and tasks on the overview tab
Wrap the DX cards so the entity identifier comes from the Backstage entity. Then place the cards in your overview content.
// packages/app/src/components/catalog/EntityPage.tsx
import React from 'react';
import Grid from '@material-ui/core/Grid';
import { useEntity } from '@backstage/plugin-catalog-react';
import { EntityAboutCard } from '@backstage/plugin-catalog';
import {
EntityScorecardsCard,
EntityTasksCard,
} from '@get-dx/backstage-plugin';
function EntityScorecardsCardWrapped() {
const { entity } = useEntity();
const entityIdentifier =
entity.metadata.annotations?.['getdx.com/id'] ?? entity.metadata.name;
return <EntityScorecardsCard entityIdentifier={entityIdentifier} />;
}
function EntityTasksCardWrapped() {
const { entity } = useEntity();
const entityIdentifier =
entity.metadata.annotations?.['getdx.com/id'] ?? entity.metadata.name;
return <EntityTasksCard entityIdentifier={entityIdentifier} />;
}
const overviewContent = (
<Grid container spacing={3} alignItems="stretch">
<Grid item md={8} sm={12}>
<EntityAboutCard variant="gridItem" />
</Grid>
<Grid item md={4} sm={12}>
<EntityScorecardsCardWrapped />
</Grid>
<Grid item md={4} sm={12}>
<EntityTasksCardWrapped />
</Grid>
</Grid>
);
export default overviewContent;
Use the custom data chart card
You can render custom metrics from DX datafeeds. Put the card on the service page or overview tab.
// packages/app/src/components/catalog/EntityPage.tsx
import React from 'react';
import Grid from '@material-ui/core/Grid';
import { useEntity } from '@backstage/plugin-catalog-react';
import { DxDataChartCard } from '@get-dx/backstage-plugin';
function DeployFrequencyChart() {
const { entity } = useEntity();
const teamId = entity.metadata.annotations?.['getdx.com/id'];
return (
<DxDataChartCard
title="Deployment Frequency"
description="Weekly deployments over time"
datafeedToken="your-datafeed-token"
unit="deployments"
variables={{ teamId }}
chartConfig={{
type: 'line',
xAxis: 'date',
yAxis: 'count',
}}
/>
);
}
const extraContent = (
<Grid container spacing={3} alignItems="stretch">
<Grid item md={6} sm={12}>
<DeployFrequencyChart />
</Grid>
</Grid>
);
export default extraContent;
You can also render a table
<DxDataChartCard
title="Recent Deployments"
description="Last 10 deployments"
datafeedToken="your-datafeed-token"
unit="deployments"
chartConfig={{
type: 'table',
}}
/>
Map Backstage entities to DX entity identifiers
If your DX identifier matches the Backstage entity name, pass entity.metadata.name. If you store the DX id in an annotation, prefer that. The wrappers shown earlier handle both cases.
Changelog
This changelog is produced from commits made to the DX plugin since 4 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.
Breaking changes
- #37 Remove page based pagination from scorecards and tasks APIs. The plugin now uses cursor pagination. Merged 2 months ago
- #36 Remove old DORA components and related helpers. Move to DxDataChart. Merged 3 months ago
Features
- #36 Add DxDataChart component. Mark as v1. Merged 3 months ago
- #32 Add CheckResultDrawer to EntityScorecardsPage and EntityScorecardsCard. Show the check message and related property. Merged 4 months ago
- #33 Add optional errorFallback prop to each component. Lets you customize error handling. Merged 4 months ago
Documentation
- #35 Update README with missing import for useEntity. Merged 2 months ago
Set up Backstage in minutes with Roadie
Focus on using Backstage, rather than building and maintaining it.