End of life means a version has reached the end of support from its maintainer. Security patches stop. New bugs stay unfixed. For engineers who run many services, this creates risk. You need a clear view of what will expire and when.
The End of life plugin adds that view to your Backstage catalog. It shows the lifecycle of the tech behind each entity. Data comes from endoflife.date. You can point it at your own source if you track lifecycles internally. The plugin surfaces supported versions, important dates, and a simple status so teams can see what needs attention. It lives with the rest of your service data, so the context is always there.
Common uses include upgrade planning and risk reviews. You can spot aging frameworks, runtimes, and databases across your catalog. Service owners can plan migrations before support ends. Platform teams can highlight problem areas to leadership with less manual work. API producers can make version lifecycles visible to consumers. The plugin helps keep the catalog trustworthy by making stale versions hard to ignore.
Data quality matters. If a product entry is wrong or missing in the source, it may show up that way in the card. Many teams fix this by contributing updates back to the community source or by providing an internal feed.
Installation Instructions
These instructions apply to self-hosted Backstage only. To use this plugin on Roadie, visit the docs.
Install the frontend package
Run this from the Backstage root
yarn --cwd packages/app add @dweber019/backstage-plugin-endoflife
Add the card to the Entity page
Import the card and the guard. Then place the card in your Entity page so users can see it.
// packages/app/src/components/catalog/EntityPage.tsx
import React from 'react';
import Grid from '@material-ui/core/Grid';
import { EntityLayout, EntitySwitch } from '@backstage/plugin-catalog';
import {
EntityEndOfLifeCard,
isEndOfLifeAvailable,
} from '@dweber019/backstage-plugin-endoflife';
// keep your existing imports and code above
const overviewContent = (
<Grid container spacing={3} alignItems="stretch">
{/* keep your existing content */}
<EntitySwitch>
<EntitySwitch.Case if={isEndOfLifeAvailable}>
<Grid item md={6}>
<EntityEndOfLifeCard />
</Grid>
</EntitySwitch.Case>
</EntitySwitch>
</Grid>
);
// if you have a resource page layout you can also add the card there
const resourcePage = (
<EntityLayout.Route path="/" title="Overview">
<Grid container spacing={3} alignItems="stretch">
<EntitySwitch>
<EntitySwitch.Case if={isEndOfLifeAvailable}>
<Grid item md={6}>
<EntityEndOfLifeCard variant="gridItem" />
</Grid>
</EntitySwitch.Case>
</EntitySwitch>
</Grid>
</EntityLayout.Route>
);
// keep your existing exports
Add entity annotations
Use the product name from the endoflife site path. You can set a single product or several. You can also pin a version cycle with the at symbol.
apiVersion: backstage.io/v1alpha1
kind: Resource
metadata:
name: eol-angular
annotations:
endoflife.date/products: angular
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: eol-angular-nginx-app
annotations:
endoflife.date/products: angular,nginx
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: eol-angular-nignx-version-app
annotations:
endoflife.date/products: angular@17,[email protected]
Load data from a custom url if you do not want to use the public service
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: angular-app
annotations:
endoflife.date/url-location: https://example.com/versions.json
Load data from your source repository
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: angular-app
annotations:
endoflife.date/source-location: /versions.json
The source location path is relative to the repository root
Do not mix these annotations in one entity
The lookup order is products then url location then source location
Configure help text or a custom base url
Set optional app config for the help text shown in the card. You can also point the plugin to a private End of life service.
# app-config.yaml
endOfLife:
helpText: |
# Custom help text
You can use markdown if you like
baseUrl: https://endoflife.mycompany.com
Install the backend for source location support
This is only needed if you use the source location annotation. It enables the backend to read the file from your repository through your configured integrations.
yarn --cwd packages/backend add @dweber019/backstage-plugin-endoflife-backend
New backend system
Register the backend plugin in your backend startup file.
// packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';
import { endOfLifePlugin } from '@dweber019/backstage-plugin-endoflife-backend';
const backend = createBackend();
// add your other plugins here
backend.add(endOfLifePlugin());
// start the backend
backend.start();
If your project uses a builder style
// packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-app-api';
import { endOfLifePlugin } from '@dweber019/backstage-plugin-endoflife-backend';
const backend = createBackend();
// other registrations
backend.add(endOfLifePlugin());
await backend.start();
Legacy backend system
Create the router and mount it under the api path.
// packages/backend/src/plugins/endoflife.ts
import { PluginEnvironment } from '../types';
import { createRouter } from '@dweber019/backstage-plugin-endoflife-backend';
export default async function createPlugin(env: PluginEnvironment) {
return await createRouter({
logger: env.logger,
config: env.config,
reader: env.reader,
discovery: env.discovery,
});
}
Mount the router in the main backend
// packages/backend/src/index.ts
import endoflife from './plugins/endoflife';
// inside the main bootstrap where you set up apiRouter
const endoflifeEnv = useHotMemoize(module, () => createEnv('endoflife'));
apiRouter.use('/endoflife', await endoflife(endoflifeEnv));
Notes on usage
- Use the card anywhere on an entity page where users will see it
- The source location annotation requires the backend in place
- The plugin reads from the public endoflife service by default unless you set a custom base url in app config
Changelog
This changelog is produced from commits made to the End of life 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
- Enable custom url for data in the End of life plugin #103 3 months ago
- Add annotation parameters trim to reduce errors when reading annotations #98 4 months ago
Maintenance
- Update Backstage to 1.41.1 for the plugin and backend #108 2 months ago
- Update Backstage to 1.41.0 and remove React imports #101 3 months ago
- Update Backstage to 1.36.1 #92 6 months ago
- Update Backstage to 1.35.0 #86 8 months ago
- Update Backstage to 1.34.2 #84 9 months ago
- Update Backstage dependencies to 1.32.2 #77 11 months ago
Set up Backstage in minutes with Roadie
Focus on using Backstage, rather than building and maintaining it.