Home logo

Backstage Home Plugin

Created by Spotify

Home is the plugin that lets you build a real start page for Backstage. It surfaces important info and simple shortcuts in one place. You compose it with cards then let teams personalize the layout with a flexible grid that supports adding, moving, and saving widgets.

It ships with useful pieces you can drop in. Show a search bar, starred entities, featured docs, a quick start card, a company logo, and more. You can also track what people use. The plugin records visits so you can display recently visited pages and top visited pages for quick return paths. These cards help people pick up where they left off.

Typical use cases include a portal launcher with links to tools, a status corner for docs or runbooks, and a personalized dashboard for each engineer. It works well when you want a home page that reflects how your org works without forcing a single layout.

Companies use this pattern today. Spotify says their Backstage homepage is one of the most commonly used pages and helps people quickly find and access things.

Installation Instructions

These instructions apply to self-hosted Backstage only. To use this plugin on Roadie, visit the docs.

Install the package

  1. From the repo root change into your app package
Copy
cd packages/app
  1. Add the Home plugin
Copy
yarn add @backstage/plugin-home

Create the home page component

  1. Create the file packages/app/src/components/home/HomePage.tsx

  2. Add a simple layout. You can swap in any of the exported components later

Copy
// packages/app/src/components/home/HomePage.tsx
import Grid from '@material-ui/core/Grid';
import {
  HomePageRandomJoke,
  HomePageStarredEntities,
  HomePageTopVisited,
  HomePageRecentlyVisited,
  QuickStartCard,
} from '@backstage/plugin-home';

export const homePage = (
  <Grid container spacing={3}>
    <Grid item xs={12} md={6}>
      <HomePageRandomJoke />
    </Grid>
    <Grid item xs={12} md={6}>
      <HomePageStarredEntities />
    </Grid>
    <Grid item xs={12} md={6}>
      <HomePageTopVisited />
    </Grid>
    <Grid item xs={12} md={6}>
      <HomePageRecentlyVisited />
    </Grid>
    <Grid item xs={12} md={6}>
      <QuickStartCard
        title="Onboarding"
        modalTitle="Getting started"
        docsLinkTitle="Learn more"
        docsLink="https://backstage.io/docs/getting-started"
        image={<img src="/static/logo.png" alt="quick start" width="100%" height="100%" />}
        cardDescription="Helpful links for new users"
      />
    </Grid>
  </Grid>
);

Add the route

  1. Open packages/app/src/App.tsx

  2. Import the composition root and your home page element

  3. Add the route at the root path

Copy
// packages/app/src/App.tsx
import React from 'react';
import { AlertDisplay, OAuthRequestDialog } from '@backstage/core-components';
import { AppRouter } from '@backstage/core-app-api';
import { HomepageCompositionRoot, VisitListener } from '@backstage/plugin-home';
import { homePage } from './components/home/HomePage';
// other imports for your routes

export default app.createRoot(
  <>
    <AlertDisplay />
    <OAuthRequestDialog />
    <AppRouter>
      <VisitListener />
      <Routes>
        <Route path="/" element={<HomepageCompositionRoot />}>
          {homePage}
        </Route>

        {/* keep your other routes here */}
      </Routes>
    </AppRouter>
  </>,
);

The HomepageCompositionRoot renders the page shell for the home route. The homePage element you created becomes the page content.

Track page visits

Home offers two cards that need visit data

  • HomePageTopVisited
  • HomePageRecentlyVisited

Add the VisitListener once in your app root to record visits as users navigate. The snippet above already shows it placed just inside AppRouter.

Provide the visits API

Add a visits API implementation to your app APIs. Pick one of the two options.

  1. Open packages/app/src/apis.ts

  2. Import the references

  3. Register at least one implementation

Using storageApi for persistence linked to the signed in user

Copy
// packages/app/src/apis.ts
import {
  AnyApiFactory,
  createApiFactory,
  identityApiRef,
  storageApiRef,
  errorApiRef,
} from '@backstage/core-plugin-api';

import {
  visitsApiRef,
  VisitsStorageApi,
} from '@backstage/plugin-home';

// keep your other api factories

export const apis: AnyApiFactory[] = [
  // other api factories

  createApiFactory({
    api: visitsApiRef,
    deps: { storageApi: storageApiRef, identityApi: identityApiRef },
    factory: ({ storageApi, identityApi }) =>
      VisitsStorageApi.create({ storageApi, identityApi }),
  }),
];

Or use localStorage in the browser

Copy
// packages/app/src/apis.ts
import {
  AnyApiFactory,
  createApiFactory,
  identityApiRef,
  errorApiRef,
} from '@backstage/core-plugin-api';

import {
  visitsApiRef,
  VisitsWebStorageApi,
} from '@backstage/plugin-home';

// keep your other api factories

export const apis: AnyApiFactory[] = [
  // other api factories

  createApiFactory({
    api: visitsApiRef,
    deps: { identityApi: identityApiRef, errorApi: errorApiRef },
    factory: ({ identityApi, errorApi }) =>
      VisitsWebStorageApi.create({ identityApi, errorApi }),
  }),
];

Optional customizable home page

You can let users add move configure or remove widgets. Replace your static grid with CustomHomepageGrid. Add the widgets you allow inside the grid.

Copy
// packages/app/src/components/home/HomePage.tsx
import {
  CustomHomepageGrid,
  HomePageRandomJoke,
  HomePageStarredEntities,
  HomePageTopVisited,
  HomePageRecentlyVisited,
} from '@backstage/plugin-home';

export const homePage = (
  <CustomHomepageGrid title="Your Dashboard">
    <HomePageRandomJoke />
    <HomePageStarredEntities />
    <HomePageTopVisited />
    <HomePageRecentlyVisited />
  </CustomHomepageGrid>
);

Optional default layout for the customizable grid

Pass a default config that defines starting positions and sizes.

Copy
// packages/app/src/components/home/HomePage.tsx
import {
  CustomHomepageGrid,
  HomePageStarredEntities,
} from '@backstage/plugin-home';

const defaultConfig = [
  {
    component: 'HomePageStarredEntities',
    x: 0,
    y: 0,
    width: 6,
    height: 4,
    movable: true,
    resizable: true,
    deletable: false,
  },
];

export const homePage = (
  <CustomHomepageGrid title="Your Dashboard" config={defaultConfig} />
);

You can use the component element instead of a string if you prefer

Copy
const defaultConfig = [
  {
    component: <HomePageStarredEntities />,
    x: 0,
    y: 0,
    width: 6,
    height: 4,
  },
];

Optional filter for visits in app config

You can filter what the visit cards show. Add this in app-config.yaml

Copy
home:
  recentVisits:
    filterBy:
      - field: name
        operator: contains
        value: service
  topVisits:
    filterBy:
      - field: hits
        operator: '>='
        value: 2

Run the Backstage config checker if you want to validate the structure

Copy
yarn backstage-cli config:check

Backend install notes

This plugin does not ship a backend plugin. You do not need to add anything to the legacy backend system. You do not need to add anything to the new backend system. The visit storage runs in the browser or in the app storage API.

Changelog

This changelog is produced from commits made to the Home 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.

Features

  • Add i18n support to the home plugin #30140 4 months ago
  • Add App Root Elements for VisitListener and SignalsDisplay in the new frontend system #30454 3 months ago
  • Add the missing visits API in the new frontend system #30574 2 months ago

Bug fixes

  • Fix clear all in CustomHomepageGrid to respect the deletable flag default. Widgets marked as not deletable stay. Others remove by default #30994 2 days ago
  • Wait for storage to load before rendering the custom homepage layout. Prevents a brief flicker of default widgets #31085 1 month ago
  • Fix clear all so it does not remove widgets marked as not deletable #30788 2 months ago
  • Fix WelcomeTitle to default to inherit as before #30171 4 months ago

Breaking changes

  • Blueprints with advanced param types now use a define callback form. Update ApiBlueprint usage to params define => define options #30673 2 months ago
  • AppRootElementBlueprint now only accepts an element #30703 2 months ago
  • Remove the default prefix from blueprint param names. Update any code that used that prefix #30721 2 months ago
  • FrontendPlugin no longer exposes override methods. Use OverridableFrontendPlugin if you need overrides #30904 2 months ago

Documentation

  • Recommend the name defineParams for blueprint param helpers #30714 2 months ago

Set up Backstage in minutes with Roadie