Backstage Search gives your developer portal a single place to find things. It plugs into the Backstage frontend with a search page and a quick search modal. It also adds a backend that crawls sources and serves results through a simple API. Together these parts let teams search code metadata, docs, and custom data from one box.
The plugin indexes content from the software catalog and TechDocs. You can add your own collators to bring in data from any system you run. The architecture supports multiple engines so teams can start small then scale. Elasticsearch is recommended for production due to better scale and filtering. Common result views are ready to use. You can also build custom result items that show the fields that matter to your teams.
If you run a self hosted Backstage, this plugin helps engineers find services, docs, templates, and APIs fast. It cuts the time spent jumping between tools and gives a consistent search experience across your portal.
Installation Instructions
These instructions apply to self-hosted Backstage only.
Install the backend on the new backend system
Add the packages
yarn --cwd packages/backend add @backstage/plugin-search-backend @backstage/plugin-search-backend-module-catalog @backstage/plugin-search-backend-module-techdocs
Register the backend plugins
Put this in packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';
const backend = createBackend();
// Search core
backend.add(import('@backstage/plugin-search-backend'));
// Index Software Catalog entities
backend.add(import('@backstage/plugin-search-backend-module-catalog'));
// Index TechDocs content
backend.add(import('@backstage/plugin-search-backend-module-techdocs'));
backend.start();
Optional config for collators
You can tune schedule or filters for the collators in app-config.yaml
search:
collators:
catalog:
schedule:
frequency:
minutes: 30
timeout:
minutes: 10
initialDelay:
seconds: 10
# optional example filter
filter:
kind: [Component, API]
techdocs:
schedule:
frequency:
minutes: 30
timeout:
minutes: 15
initialDelay:
seconds: 10
Add the frontend so users can search
Add the packages
yarn --cwd packages/app add @backstage/plugin-search @backstage/plugin-search-react
Add the Search page route
Edit packages/app/src/App.tsx
import React from 'react';
import { Route } from 'react-router';
import { FlatRoutes } from '@backstage/core-app-api';
import { SearchPage } from '@backstage/plugin-search';
// keep your other imports
export const App = () => (
<FlatRoutes>
{/* your other routes */}
<Route path="/search" element={<SearchPage />} />
</FlatRoutes>
);
Link to the Search page in the sidebar
Edit packages/app/src/components/Root/Root.tsx
import React from 'react';
import { Sidebar, SidebarItem } from '@backstage/core-components';
import SearchIcon from '@mui/icons-material/Search';
// keep your other imports
export const Root = ({ children }: { children?: React.ReactNode }) => (
<>
<Sidebar>
{/* your other sidebar items */}
<SidebarItem to="/search" icon={SearchIcon} text="Search" />
</Sidebar>
{children}
</>
);
Old backend system setup
The current search backend dropped legacy support in major version two. If you still run the old backend system you need a one x release of the search backend.
Add the packages
yarn --cwd packages/backend add @backstage/plugin-search-backend@^1.8.2 @backstage/plugin-search-backend-node
If your backend does not already have the catalog backend
yarn --cwd packages/backend add @backstage/plugin-catalog-backend
Create the search plugin file
Create packages/backend/src/plugins/search.ts
import { useHotCleanup } from '@backstage/backend-common';
import { createRouter } from '@backstage/plugin-search-backend';
import {
IndexBuilder,
LunrSearchEngine,
} from '@backstage/plugin-search-backend-node';
import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
import { PluginEnvironment } from '../types';
export default async function createPlugin({
logger,
discovery,
}: PluginEnvironment) {
const searchEngine = new LunrSearchEngine({ logger });
const indexBuilder = new IndexBuilder({ logger, searchEngine });
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: new DefaultCatalogCollator({ discovery }),
});
const { scheduler } = await indexBuilder.build();
setTimeout(() => scheduler.start(), 3000);
useHotCleanup(module, () => scheduler.stop());
return await createRouter({
engine: indexBuilder.getSearchEngine(),
logger,
});
}
Mount the search router
Edit packages/backend/src/index.ts
import search from './plugins/search';
import { useHotMemoize } from '@backstage/backend-common';
// inside your main bootstrap function
const searchEnv = useHotMemoize(module, () => createEnv('search'));
apiRouter.use('/search', await search(searchEnv));
Optional search config
You can tune some backend limits
search:
maxTermLength: 100
That is it. Install the packages, wire the backend, add the Search page route, add a sidebar link. When you run the app the Search page is reachable at path slash search.
Set up Backstage in minutes with Roadie
Focus on using Backstage, rather than building and maintaining it.