Skip to main content
Version: Next

Backstage homepage - Setup and Customization

info

This documentation is written for the new frontend system, which is the default in new Backstage apps. If your Backstage app still uses the old frontend system, read the old frontend system version of this guide instead.

Homepage

The Home plugin gives your Backstage app a homepage where users can find what they need without memorizing URLs. It ships with a drag-and-drop grid layout and a set of built-in widgets. Users can add, remove, rearrange, and resize widgets, and their layout is saved per user.

This guide covers:

  • Installing the home plugin and making it your landing page.
  • What widgets are available and how to configure them.
  • How to create your own widgets and layouts.

Prerequisites

Before you begin, make sure:

  • You have created your own standalone Backstage app using @backstage/create-app and not using a fork of the backstage repository.
  • You do not have an existing homepage, and by default you are redirected to the Software Catalog when you open Backstage.

Setup

1. Install the plugin

From your Backstage root directory
yarn --cwd packages/app add @backstage/plugin-home

Once installed, the plugin is available in your app through default feature discovery. See installing plugins for alternative installation methods.

2. Configure the homepage as your root route

The homepage lives at /home by default. To make it your landing page at /, add this to your app-config.yaml:

app-config.yaml
app:
extensions:
- page:home:
config:
path: /

The plugin adds a "Home" navigation item to your sidebar automatically.

3. Enable visit tracking (optional)

Visit tracking records which pages users navigate to. The Most Visited and Recently Visited widgets use this data. It is disabled by default.

When enabled, visit data is stored in one of two places:

  • UserSettings storage (recommended) if you have the UserSettings plugin with persistent storage. Data syncs across devices.
  • Browser local storage as a fallback if no persistent storage is available.

To enable it, add these extensions to your app-config.yaml:

app-config.yaml
app:
extensions:
- api:home/visits: true
- app-root-element:home/visit-listener: true

Available widgets

The following widgets are available out of the box and appear in the Add Widget dialog when editing the homepage.

Home plugin widgets

These widgets come from @backstage/plugin-home:

WidgetExtension IDDescription
Starred Entitieshome-page-widget:home/starred-entitiesShows entities you have starred in the catalog.
Toolkithome-page-widget:home/toolkitA collection of configurable links and tools.
World Clockshome-page-widget:home/world-clockDisplays clocks for configured time zones.
Most Visitedhome-page-widget:home/most-visitedShows your most frequently visited pages. Requires visit tracking.
Recently Visitedhome-page-widget:home/recently-visitedShows pages you have recently visited. Requires visit tracking.
Random Jokehome-page-widget:home/random-jokeShows a random programming joke.

Search plugin widget

This widget comes from @backstage/plugin-search:

WidgetExtension IDDescription
Search Barhome-page-widget:search/search-barA search bar that navigates to the search page on submit.
note

The search bar widget requires @backstage/plugin-search to be installed.

Community widgets

The Backstage community-plugins repository hosts additional plugins, some of which provide homepage widgets. Any plugin can contribute widgets to the homepage by using the HomePageWidgetBlueprint from @backstage/plugin-home-react/alpha.

Configuring widgets

Some widgets accept configuration through app-config.yaml. Target a widget using its extension ID.

Toolkit

The Toolkit widget shows a grid of links. You can configure the links and their icons:

app-config.yaml
app:
extensions:
- home-page-widget:home/toolkit:
config:
tools:
- url: https://backstage.io/docs
label: Docs
icon: docs
- url: https://github.com/backstage/backstage
label: GitHub
icon: github
- url: https://backstage.io/plugins
label: Plugins Directory
icon: kind:component

The icon field resolves through the app's icon API. You can use any registered icon, including kind: prefixed icons for catalog entity kinds.

World Clocks

Configure which time zones to display and the time format:

app-config.yaml
app:
extensions:
- home-page-widget:home/world-clock:
config:
customTimeFormat:
hour12: false
clockConfigs:
- label: NYC
timeZone: America/New_York
- label: UTC
timeZone: UTC
- label: STO
timeZone: Europe/Stockholm
- label: TYO
timeZone: Asia/Tokyo

Disabling a widget

To hide a widget from the Add Widget dialog, set it to false:

app-config.yaml
app:
extensions:
- home-page-widget:home/random-joke: false

Configuring the default layout

The defaultConfig option on page:home defines the grid layout that users see before they have customized anything. Each entry places a widget at a specific position and size in the grid:

app-config.yaml
app:
extensions:
- page:home:
config:
path: /
defaultConfig:
- component: HomePageSearchBar
column: 0
row: 0
width: 12
height: 2
deletable: false
- component: HomePageStarredEntities
column: 0
row: 2
width: 4
height: 4
- component: HomePageToolkit
column: 4
row: 2
width: 4
height: 3
- component: HomePageWorldClock
column: 8
row: 2
width: 4
height: 3

Each item in defaultConfig accepts these properties:

PropertyTypeDescription
componentstringThe widget's component name (the name parameter from the blueprint).
columnnumberThe column position in the grid (0-based).
rownumberThe row position in the grid (0-based).
widthnumberThe width in grid columns. The default grid has 12 columns.
heightnumberThe height in grid rows.
movablebooleanWhether the user can move the widget. Defaults to true.
deletablebooleanWhether the user can remove the widget. Defaults to true.
resizablebooleanWhether the user can resize the widget. Defaults to true.
tip

In edit mode, each widget displays its column, row, width, and height values. Use these to figure out the right numbers for your defaultConfig.

Creating custom widgets

You can add your own widgets using the HomePageWidgetBlueprint from @backstage/plugin-home-react/alpha. Define the widget, wrap it in a frontend module, and register it in your app.

A basic widget

packages/app/src/modules/home/homeModule.tsx
import { createFrontendModule } from '@backstage/frontend-plugin-api';
import { HomePageWidgetBlueprint } from '@backstage/plugin-home-react/alpha';

const myWidget = HomePageWidgetBlueprint.make({
name: 'my-widget',
params: {
name: 'MyWidget',
title: 'My Custom Widget',
description: 'A short description shown in the Add Widget dialog',
components: () =>
import('./MyWidgetComponent').then(m => ({
Content: m.Content,
})),
},
});

export const homeModule = createFrontendModule({
pluginId: 'home',
extensions: [myWidget],
});

Then register the module in your app:

packages/app/src/App.tsx
import { homeModule } from './modules/home';

export default createApp({
features: [homeModule],
});

Widget with layout constraints

Set minimum and maximum dimensions so the widget does not get too small or too large:

const myWidget = HomePageWidgetBlueprint.make({
name: 'my-widget',
params: {
name: 'MyWidget',
title: 'My Custom Widget',
description: 'A widget with size constraints',
components: () =>
import('./MyWidgetComponent').then(m => ({
Content: m.Content,
})),
layout: {
height: { minRows: 4 },
width: { minColumns: 3 },
},
},
});

Widget with user settings

Widgets can expose per-user settings. The settings schema follows react-jsonschema-form conventions:

const myWidget = HomePageWidgetBlueprint.make({
name: 'my-widget',
params: {
name: 'MyWidget',
title: 'My Custom Widget',
description: 'A widget with user-configurable settings',
components: () =>
import('./MyWidgetComponent').then(m => ({
Content: m.Content,
Settings: m.Settings,
})),
settings: {
schema: {
title: 'Widget Settings',
type: 'object',
properties: {
color: {
title: 'Color',
type: 'string',
default: 'blue',
enum: ['blue', 'red', 'green'],
},
},
},
},
},
});

Custom homepage layouts

If the default grid does not fit your needs, you can replace it entirely. Use the HomePageLayoutBlueprint from @backstage/plugin-home-react/alpha to create a layout component that receives the installed widgets and renders them however you want.

packages/app/src/modules/home/homeModule.tsx
import { createFrontendModule } from '@backstage/frontend-plugin-api';
import {
HomePageLayoutBlueprint,
type HomePageLayoutProps,
} from '@backstage/plugin-home-react/alpha';
import { CustomHomepageGrid } from '@backstage/plugin-home';
import { Content, Header, Page } from '@backstage/core-components';
import { Fragment } from 'react';

const myLayout = HomePageLayoutBlueprint.make({
params: {
loader: async () =>
function MyHomePageLayout({ widgets }: HomePageLayoutProps) {
return (
<Page themeId="home">
<Header title="Welcome" />
<Content>
<CustomHomepageGrid>
{widgets.map((widget, index) => (
<Fragment key={widget.name ?? index}>
{widget.component}
</Fragment>
))}
</CustomHomepageGrid>
</Content>
</Page>
);
},
},
});

export const homeModule = createFrontendModule({
pluginId: 'home',
extensions: [myLayout],
});

When no custom layout is installed, the plugin falls back to a built-in default that renders widgets inside CustomHomepageGrid.

Preventing duplicate widgets

By default, users can add multiple instances of the same widget. If you are using a custom layout with CustomHomepageGrid, you can restrict each widget to a single instance by passing the preventDuplicateWidgets prop. This option requires a custom layout. It is not exposed as an app-config setting.

<CustomHomepageGrid preventDuplicateWidgets>
{widgets.map((widget, index) => (
<Fragment key={widget.name ?? index}>{widget.component}</Fragment>
))}
</CustomHomepageGrid>