Building Backstage frontend plugins with the New Frontend System: createFrontendPlugin, extension points, components, pages, and dependency injection, using React hooks like useEntity to extend the entity page, and styling with MUI after the move away from Blueprint in 2026.

In episode 16, you built search that unifies all information sources. Episode 17 shifts your role: from a Backstage user to a frontend plugin creator. This is the start of Phase 5, where you extend the portal to fit your organization's needs. The frontend is Backstage's face — the plugins you write are what thousands of engineers see and use every day, so understanding how to build them correctly is the most visible skill in this entire series.
Backstage now uses the New Frontend System as the default way to build frontend plugins. Instead of every plugin managing itself freely, the New Frontend System introduces the concept of extensions — declarative units that can be contributed and wired to each other. Frontend plugins are created with createFrontendPlugin, imported from @backstage/frontend-plugin-api:
import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
const examplePlugin = createFrontendPlugin({
id: 'example',
extensions: [
examplePage,
exampleEntityCard,
],
});This declaration is quite simple: a plugin has a unique id and a list of extensions it contributes. The frontend core places those extensions into their respective locations.
The core of the New Frontend System is extension points: contracts that define where and how something can be injected. There are two sides:
The two extension types you'll write most often are pages and components:
const examplePage = createExtension({
id: 'example.page',
at: createExtensionPoint({ id: 'core.routes' }),
output: {
element: () => <ExamplePage />,
},
});Pages mount to frontend routes; components mount to other locations like the entity page. By separating "where" from "what", a single page can be remounted in several places without rewriting code.
A frontend plugin rarely works alone — it needs services from other plugins. The New Frontend System provides dependency injection: a plugin declares its dependencies, and the framework injects already-wired instances. This pattern is used through the inputs declaration on an extension:
const exampleExtension = createExtension({
id: 'example.deps',
at: someExtensionPoint,
inputs: {
cards: {
extensionPoint: cardExtensionPoint,
required: false,
},
},
output: {
element: ({ inputs }) => (
<Layout>
{inputs.cards}
</Layout>
),
},
});With dependency injection, you don't need to import global instances or guess how to initialize things — the framework manages the lifecycle and the wiring between extensions.
The majority of Backstage plugins deal with catalog entities. The useEntity hook provides the data of the entity currently being viewed, complete with its metadata and relations:
import { useEntity } from '@backstage/plugin-catalog-react';
const MyEntityCard = () => {
const { entity } = useEntity();
return (
<Card>
<Typography variant="h6">{entity.metadata.name}</Typography>
<Typography>{entity.metadata.description}</Typography>
</Card>
);
};useEntity is the bridge between your plugin and the currently active entity context. There's no need to read the URL or guess which entity is being viewed — the context provided by the catalog answers that.
To display content on the entity page, you connect extensions to the extension points provided by the catalog. An EntityCard appears as a card on an entity tab, while an EntityPage lets you add a new tab to the entity page. With this approach, every plugin can "insert itself" into the entity page without touching the core catalog code — the best example of the power of extension points.
For appearance, Backstage uses MUI as its primary component and styling library. Since 2026, Backstage core has completed its move from Blueprint to MUI — so all new and actively maintained plugins should use MUI to stay consistent with the portal's default theme.
| Concept | Role |
|---|---|
| ThemeProvider | Provides the global theme to components |
| Typography | Consistent text hierarchy |
| Card | Standard content container |
| Grid | Responsive layout |
When writing a new plugin, take advantage of MUI components and the existing Backstage theme instead of bringing your own styling library — the result blends into the portal rather than looking bolted on.
Note
If you come across old plugin code using Blueprint, don't be afraid to migrate it to MUI. The component mapping is fairly straightforward: Blueprint components have MUI equivalents for almost every case, and the Backstage theme already handles most of the details.
Episode 17 opened the door to frontend plugin development: the New Frontend System with createFrontendPlugin, extension points for defining and receiving contributions, pages and components as extension forms, dependency injection for wiring dependencies, useEntity for reading the active entity, extending the entity page through EntityCard and EntityPage, and styling with MUI after the migration from Blueprint.
The key takeaways:
In the next episode, episode 18, you switch to the other side: backend plugin & backend framework — createBackendPlugin and createBackendModule, service APIs, plugin options, and testing with backend-test-utils. Your frontend and backend will complement each other into a complete plugin.