Jira is where many teams plan and track work.
The Jira Dashboard plugin brings that work into Backstage so you can see issues next to the services you own. It shows project context and the current state of tickets without leaving your developer portal.The plugin fetches Jira issues for a Backstage entity. You get quick views for incoming items, open items, and tickets assigned to you. It supports Jira Software and Jira Cloud. You can tailor what appears by using Jira filters, components, or your own JQL so each team sees the data that matters.Common use cases include daily triage, sprint planning, and on call reviews. Teams keep an eye on priority, assignee, and status from one place. The overview sits under a Jira Dashboard tab on the entity page, which keeps navigation simple for service owners.
Axis Communications created and maintains the plugin. They note “At Axis, we’ve developed our own set of plugins exclusively available to us. Now, we’re eager to share these with other companies.” This reflects real use at a product company that ships software at scale.
If you already rely on Jira and you run Backstage yourself, this plugin helps cut context switching. It keeps your project signals in view so you can move faster with fewer tabs.
Installation Instructions
These instructions apply to self-hosted Backstage only.
Install the frontend plugin in a classic Backstage app
- Add the plugin to the app package
yarn --cwd packages/app add @axis-backstage/plugin-jira-dashboard
- Add the route on the entity page
// packages/app/src/components/catalog/EntityPage.tsx
import { EntityJiraDashboardContent, isJiraDashboardAvailable } from '@axis-backstage/plugin-jira-dashboard';
// inside your defaultEntityPage definition
<EntityLayout.Route
if={isJiraDashboardAvailable}
path="/jira-dashboard"
title="Jira Dashboard"
>
<EntityJiraDashboardContent />
</EntityLayout.Route>
- Optional change the annotation prefix used by the availability check
If you use a custom annotation prefix, pass it to the helper. Make sure the backend uses the same prefix value.
// packages/app/src/components/catalog/EntityPage.tsx
import { EntityJiraDashboardContent, isJiraDashboardAvailable } from '@axis-backstage/plugin-jira-dashboard';
// inside your defaultEntityPage definition
<EntityLayout.Route
if={entity => isJiraDashboardAvailable(entity, 'jira')}
path="/jira-dashboard"
title="Jira Dashboard"
>
<EntityJiraDashboardContent />
</EntityLayout.Route>
- Add catalog annotations on each entity that should show Jira data
Single project key
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
annotations:
jira.com/project-key: value
Multiple project keys
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
annotations:
jira.com/project-key: abc,bcd,def
Optional annotations
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
annotations:
jira.com/project-key: another-instance/value
jira.com/components: component,component,component
jira.com/filter-ids: 12345,67890
jira.com/incoming-issues-status: Incoming
Custom JQL for full control
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
annotations:
jira.com/jql: component = OurProject AND Affected = 1.1
Install the backend plugin in the classic backend
- Add the backend package
yarn --cwd packages/backend add @axis-backstage/plugin-jira-dashboard-backend
- Register the backend router
Create a small plugin file
// packages/backend/src/plugins/jiraDashboard.ts
import { Router } from 'express';
import { createRouter } from '@axis-backstage/plugin-jira-dashboard-backend';
import { PluginEnvironment } from '../types';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
return await createRouter({
logger: env.logger,
config: env.config,
discovery: env.discovery,
httpAuth: env.httpAuth,
identity: env.identity,
permissions: env.permissions,
});
}
Mount it in the main backend
// packages/backend/src/index.ts
import jiraDashboard from './plugins/jiraDashboard';
// inside main function after creating env for each plugin
const jiraDashboardEnv = useHotMemoize(module, () => createEnv('jira-dashboard'));
apiRouter.use('/jira-dashboard', await jiraDashboard(jiraDashboardEnv));
- Configure the backend
Add configuration for your Jira instances. Use environment variables for secrets.
# app-config.yaml
jiraDashboard:
annotationPrefix: jira
instances:
- name: default
token: ${JIRA_TOKEN}
baseUrl: https://<team>.atlassian.net/rest/api/3/
defaultFilters:
- name: 'Unresolved'
shortName: 'Unresolved'
query: 'status != Done AND status != Decline ORDER BY updated DESC, priority DESC'
Set required environment variables for the backend process
export JIRA_TOKEN='your-jira-api-token'
export JIRA_EMAIL_SUFFIX='example.com'
Use the homepage user issues card optional
Add the card to your homepage component
// packages/app/src/components/home/Homepage.tsx
import Grid from '@material-ui/core/Grid';
import { JiraUserIssuesViewCard } from '@axis-backstage/plugin-jira-dashboard';
export const Homepage = () => (
<Grid container spacing={3}>
<Grid item xs={12} md={6}>
<JiraUserIssuesViewCard
bottomLinkProps={{
link: 'https://our-jira-server/issues',
title: 'Open in Jira',
}}
/>
</Grid>
</Grid>
);
Optional custom settings
// packages/app/src/components/home/Homepage.tsx
import Grid from '@material-ui/core/Grid';
import { JiraUserIssuesViewCard } from '@axis-backstage/plugin-jira-dashboard';
export const Homepage = () => (
<Grid container spacing={3}>
<Grid item xs={12} md={6}>
<JiraUserIssuesViewCard
bottomLinkProps={{
link: 'https://our-jira-server/issues',
title: 'Open in Jira',
}}
maxResults={30}
tableOptions={{
toolbar: true,
search: true,
paging: true,
pageSize: 15,
}}
tableStyle={{
padding: '5px',
overflowY: 'auto',
width: '95%',
}}
/>
</Grid>
</Grid>
);
Optional use of a named default filter. The filter must exist in backend config
<JiraUserIssuesViewCard
bottomLinkProps={{ link: 'https://our-jira-server/issues', title: 'Open in Jira' }}
maxResults={30}
filterName="Unresolved"
/>
Example backend filter config
jiraDashboard:
annotationPrefix: jira
instances:
- name: default
token: ${JIRA_TOKEN}
baseUrl: https://<team>.atlassian.net/rest/api/3/
defaultFilters:
- name: 'Unresolved'
shortName: 'Unresolved'
query: 'status != Done AND status != Decline ORDER BY updated DESC, priority DESC'
Note. The list of user issues depends on the permissions of the token in use
Use the plugin with the new alpha frontend system optional
- Add the plugin to the app package
yarn --cwd packages/app add @axis-backstage/plugin-jira-dashboard
- Manual feature install in App only if you are not using feature discovery
// packages/app/src/arc/App.tsx
import { createApp } from '@backstage/frontend-app-api';
import jiraPlugin from '@axis-backstage/plugin-jira-dashboard/alpha';
const app = createApp({
features: [
jiraPlugin,
],
});
export default app.createRoot();
- Manual extension config in app config only if you are not using feature discovery
app:
extensions:
- entity-content:jira-dashboard/entity
Changelog
This changelog is produced from commits made to the Jira Dashboard plugin since a year 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.
Features
- Add profile card on assignee hover in Jira tables #301 (merged 1 month ago)
- Add support for jira.com/jql annotation to prefilter backend queries #314 (merged 1 month ago)
- Show project cards in tabs when multiple project keys are set #280 (merged 5 months ago)
- Add pagination to Jira tables for easier reading #268 (merged 6 months ago)
- Allow defaultFilters config to filter JiraUserIssuesViewCard data #250 (merged 8 months ago)
- Allow tableOptions on the homepage Jira table or card #223 (merged 10 months ago)
- Allow tableOptions and tableStyle props on JiraUserIssuesViewCard #248 (merged 8 months ago)
- Extract JiraUserIssuesTable for standalone use outside a card #208 (merged 10 months ago)
- Support multiple Jira project keys when building JQL #233 (merged 8 months ago)
- Improve layout on small screens for the Jira dashboard #303 (merged 2 months ago)
- Use annotationPrefix from app config so custom annotation keys work in JiraDashboardContent #236 (merged 9 months ago)
- Show the Jira tab only when the required annotation is present #263 (merged 6 months ago)
Bug fixes
- Handle assignees that have no name. Show avatar and name as before #322 (merged 3 weeks ago)
- Check that the issues field exists in Jira API responses #214 (merged 10 months ago)
- Include config d.ts in published files #243 (merged 8 months ago)
- Fix missing table options in Jira card #229 (merged 10 months ago)
Maintenance
- Bump to Backstage 1.42. Migrate Jira dashboard to the new frontend system #319 (merged 4 weeks ago)
- Bump to Backstage 1.40 #295 (merged 2 months ago)
- Bump to Backstage 1.36.1 with deprecation fixes #259 (merged 6 months ago)
- Update dependencies and peer dependencies #267 (merged 6 months ago)
- Update Jira plugin dependencies #218 (merged 10 months ago)
- Export jiraDashboardApiRef and JiraDashboardClient for manual API registration #222 (merged 10 months ago)
Documentation
- Update docs to reflect the new entity filter behavior and feature discovery setup #263 (merged 6 months ago)
Set up Backstage in minutes with Roadie
Focus on using Backstage, rather than building and maintaining it.