Backstage
Open-source internal developer portal platform by Spotify for managing software catalog and developer experience.
Installation
Section titled “Installation”Creating a New Application
Section titled “Creating a New Application”| Command | Description |
|---|---|
npx @backstage/create-app@latest | Create new Backstage application |
npx @backstage/create-app@latest --skip-install | Create app without installing dependencies |
cd my-backstage-app && yarn install | Install dependencies |
yarn dev | Start frontend and backend in development mode |
yarn start | Start frontend only |
yarn start-backend | Start backend only |
yarn build:backend | Build backend for production |
yarn build | Build all packages |
node_modules/.bin/backstage-cli --version | Show Backstage CLI version |
Docker Deployment
Section titled “Docker Deployment”| Command | Description |
|---|---|
yarn build:backend --config ../../app-config.yaml | Build backend with config |
docker build -t backstage -f packages/backend/Dockerfile . | Build Docker image |
docker run -p 7007:7007 backstage | Run Backstage container |
CLI Commands
Section titled “CLI Commands”Package Management
Section titled “Package Management”| Command | Description |
|---|---|
yarn backstage-cli package start | Start a package in dev mode |
yarn backstage-cli package build | Build a package |
yarn backstage-cli package lint | Lint package source code |
yarn backstage-cli package test | Run package tests |
yarn backstage-cli repo build --all | Build all packages in monorepo |
yarn backstage-cli repo lint --all | Lint all packages |
yarn backstage-cli versions:bump | Bump Backstage dependencies to latest |
yarn backstage-cli versions:bump --release next | Bump to next pre-release |
yarn backstage-cli migrate package-roles | Migrate packages to use roles |
Plugin Creation
Section titled “Plugin Creation”| Command | Description |
|---|---|
yarn backstage-cli create-plugin | Create new frontend plugin |
yarn backstage-cli create-plugin --backend | Create new backend plugin |
yarn backstage-cli create-plugin --id my-plugin | Create plugin with specific ID |
yarn new | Interactively create component from template |
Software Catalog
Section titled “Software Catalog”Entity Kinds
Section titled “Entity Kinds”| Command | Description |
|---|---|
Add catalog-info.yaml to repo root | Register component in catalog |
kind: Component in catalog-info.yaml | Define a software component |
kind: API in catalog-info.yaml | Define an API entity |
kind: System in catalog-info.yaml | Define a system grouping |
kind: Domain in catalog-info.yaml | Define a business domain |
kind: Resource in catalog-info.yaml | Define infrastructure resource |
kind: Group in catalog-info.yaml | Define a team/group |
kind: User in catalog-info.yaml | Define a user |
kind: Location in catalog-info.yaml | Reference other catalog files |
Entity Properties
Section titled “Entity Properties”| Command | Description |
|---|---|
Set spec.owner: team-name | Set entity ownership |
Set spec.lifecycle: production | Set entity lifecycle stage |
Set spec.type: service | Set component type (service, website, library) |
Set spec.dependsOn: ['component:other'] | Define dependencies |
Set spec.providesApis: ['api-name'] | Declare provided APIs |
Set spec.consumesApis: ['api-name'] | Declare consumed APIs |
Set spec.system: system-name | Assign to a system |
Set metadata.annotations for integrations | Connect to CI/CD, monitoring, etc. |
catalog-info.yaml Example
Section titled “catalog-info.yaml Example”apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payment-service
description: Handles payment processing and billing
annotations:
github.com/project-slug: org/payment-service
backstage.io/techdocs-ref: dir:.
jenkins.io/job-full-name: payment-service/main
pagerduty.com/service-id: PABC123
sonarqube.org/project-key: org_payment-service
tags:
- java
- payments
links:
- url: https://dashboard.example.com/payments
title: Monitoring Dashboard
icon: dashboard
- url: https://wiki.example.com/payment-service
title: Wiki
spec:
type: service
lifecycle: production
owner: team-payments
system: billing
providesApis:
- payment-api
consumesApis:
- user-api
- notification-api
dependsOn:
- resource:payments-db
- component:auth-service
API Entity Example
Section titled “API Entity Example”apiVersion: backstage.io/v1alpha1
kind: API
metadata:
name: payment-api
description: Payment processing REST API
tags:
- rest
- payments
spec:
type: openapi
lifecycle: production
owner: team-payments
system: billing
definition: |
openapi: "3.0.0"
info:
title: Payment API
version: 1.0.0
paths:
/payments:
post:
summary: Create a payment
responses:
"201":
description: Payment created
System and Domain Example
Section titled “System and Domain Example”apiVersion: backstage.io/v1alpha1
kind: System
metadata:
name: billing
description: Billing and payment processing system
spec:
owner: team-payments
domain: commerce
---
apiVersion: backstage.io/v1alpha1
kind: Domain
metadata:
name: commerce
description: E-commerce domain covering orders, payments, and fulfillment
spec:
owner: group:engineering-leadership
Templates
Section titled “Templates”Template Properties
Section titled “Template Properties”| Command | Description |
|---|---|
kind: Template in template.yaml | Define a software template |
Set spec.type: service | Template creates a service |
Set spec.steps[] for template actions | Define scaffolding steps |
action: fetch:template | Fetch and render template files |
action: publish:github | Publish scaffolded repo to GitHub |
action: publish:github:pull-request | Create PR instead of new repo |
action: catalog:register | Register created entity in catalog |
action: github:actions:dispatch | Trigger GitHub Actions workflow |
Use ${{ parameters.name }} in templates | Reference user input parameters |
Set spec.parameters[] for form fields | Define template input form |
Use ui:widget: textarea in parameters | Customize form field widget |
Template Definition Example
Section titled “Template Definition Example”apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: microservice-template
title: Create a Microservice
description: Scaffold a new microservice with CI/CD, monitoring, and docs
tags:
- recommended
- microservice
spec:
owner: team-platform
type: service
parameters:
- title: Service Details
required:
- name
- description
- owner
properties:
name:
title: Service Name
type: string
description: Unique name of the service
ui:autofocus: true
ui:options:
rows: 5
description:
title: Description
type: string
owner:
title: Owner
type: string
description: Team that owns this service
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
- title: Infrastructure
properties:
language:
title: Language
type: string
enum: ["go", "java", "python", "typescript"]
default: go
database:
title: Database
type: string
enum: ["postgres", "mysql", "none"]
default: postgres
enableMonitoring:
title: Enable Monitoring
type: boolean
default: true
steps:
- id: fetch-base
name: Fetch Base Template
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
description: ${{ parameters.description }}
owner: ${{ parameters.owner }}
language: ${{ parameters.language }}
- id: publish
name: Publish to GitHub
action: publish:github
input:
allowedHosts: ["github.com"]
repoUrl: github.com?owner=my-org&repo=${{ parameters.name }}
description: ${{ parameters.description }}
defaultBranch: main
repoVisibility: internal
- id: register
name: Register in Catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
output:
links:
- title: Repository
url: ${{ steps['publish'].output.remoteUrl }}
- title: Open in Catalog
icon: catalog
entityRef: ${{ steps['register'].output.entityRef }}
Plugins
Section titled “Plugins”Installing Plugins
Section titled “Installing Plugins”| Command | Description |
|---|---|
yarn add @backstage/plugin-catalog | Install catalog plugin |
yarn add @backstage/plugin-techdocs | Install TechDocs plugin |
yarn add @backstage/plugin-kubernetes | Install Kubernetes plugin |
yarn add @backstage/plugin-github-actions | Install GitHub Actions plugin |
yarn add @backstage/plugin-search | Install search plugin |
yarn add @backstage/plugin-scaffolder | Install scaffolder plugin |
yarn add @backstage/plugin-api-docs | Install API docs plugin |
yarn add @backstage/plugin-cost-insights | Install cost insights plugin |
Plugin Registration
Section titled “Plugin Registration”Register frontend plugins in packages/app/src/App.tsx:
import { CatalogGraphPage } from '@backstage/plugin-catalog-graph';
import { TechDocsReaderPage } from '@backstage/plugin-techdocs';
import { SearchPage } from '@backstage/plugin-search';
const routes = (
<FlatRoutes>
<Route path="/catalog" element={<CatalogIndexPage />} />
<Route path="/catalog/:namespace/:kind/:name" element={<CatalogEntityPage />}>
<EntityLayout>
<EntityLayout.Route path="/" title="Overview">
<EntityOverviewContent />
</EntityLayout.Route>
<EntityLayout.Route path="/api" title="API">
<EntityApiContent />
</EntityLayout.Route>
<EntityLayout.Route path="/docs" title="Docs">
<EntityTechDocsContent />
</EntityLayout.Route>
</EntityLayout>
</Route>
<Route path="/docs" element={<TechDocsReaderPage />} />
<Route path="/search" element={<SearchPage />} />
<Route path="/catalog-graph" element={<CatalogGraphPage />} />
</FlatRoutes>
);
Register backend plugins in packages/backend/src/index.ts:
import { createBackend } from '@backstage/backend-defaults';
const backend = createBackend();
backend.add(import('@backstage/plugin-app-backend'));
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(import('@backstage/plugin-catalog-backend-module-github-org'));
backend.add(import('@backstage/plugin-scaffolder-backend'));
backend.add(import('@backstage/plugin-techdocs-backend'));
backend.add(import('@backstage/plugin-search-backend'));
backend.add(import('@backstage/plugin-search-backend-module-catalog'));
backend.add(import('@backstage/plugin-search-backend-module-techdocs'));
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-github-provider'));
backend.add(import('@backstage/plugin-kubernetes-backend'));
backend.start();
TechDocs
Section titled “TechDocs”TechDocs Operations
Section titled “TechDocs Operations”| Command | Description |
|---|---|
npx @techdocs/cli serve | Preview TechDocs locally |
npx @techdocs/cli serve --docker-image techdocs-container | Serve using custom Docker image |
npx @techdocs/cli generate | Generate TechDocs static site |
npx @techdocs/cli generate --source-dir . | Generate from specific directory |
npx @techdocs/cli publish --publisher-type googleGcs | Publish TechDocs to GCS |
npx @techdocs/cli publish --publisher-type awsS3 | Publish TechDocs to S3 |
Add backstage.io/techdocs-ref annotation | Enable TechDocs for entity |
Create docs/ directory with mkdocs.yml | Set up TechDocs source |
Set techdocs.builder: 'local' in config | Use local TechDocs builder |
Set techdocs.builder: 'external' in config | Use external CI/CD builder |
TechDocs mkdocs.yml Example
Section titled “TechDocs mkdocs.yml Example”site_name: Payment Service
nav:
- Home: index.md
- Architecture: architecture.md
- API Reference: api-reference.md
- Runbooks:
- Deployment: runbooks/deployment.md
- Incident Response: runbooks/incident-response.md
plugins:
- techdocs-core
markdown_extensions:
- admonition
- pymdownx.highlight
- pymdownx.superfences
Search
Section titled “Search”Search Setup
Section titled “Search Setup”| Command | Description |
|---|---|
yarn add @backstage/plugin-search | Install search frontend |
yarn add @backstage/plugin-search-backend | Install search backend |
yarn add @backstage/plugin-search-backend-module-catalog | Add catalog search collator |
yarn add @backstage/plugin-search-backend-module-techdocs | Add TechDocs search collator |
Configure search engine in app-config.yaml | Set up Lunr, Elasticsearch, or PgStore |
Set search.pg in config | Use PostgreSQL for search |
Set search.elasticsearch in config | Use Elasticsearch for search |
Configuration
Section titled “Configuration”Core Settings
Section titled “Core Settings”| Command | Description |
|---|---|
Edit app-config.yaml | Main configuration file |
Edit app-config.local.yaml | Local development overrides |
Edit app-config.production.yaml | Production configuration |
Set app.baseUrl in config | Configure frontend URL |
Set backend.baseUrl in config | Configure backend URL |
Set backend.database in config | Configure database connection |
Set backend.cors.origin in config | Configure CORS origins |
Set auth.providers in config | Configure authentication providers |
Set catalog.locations[] in config | Add catalog entity sources |
Set catalog.rules[] in config | Define entity validation rules |
Set integrations.github[] in config | Configure GitHub integration token |
app-config.yaml Example
Section titled “app-config.yaml Example”app:
title: My Company Developer Portal
baseUrl: http://localhost:3000
organization:
name: My Company
backend:
baseUrl: http://localhost:7007
listen:
port: 7007
cors:
origin: http://localhost:3000
methods: [GET, HEAD, PATCH, POST, PUT, DELETE]
database:
client: pg
connection:
host: ${POSTGRES_HOST}
port: ${POSTGRES_PORT}
user: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
integrations:
github:
- host: github.com
token: ${GITHUB_TOKEN}
auth:
environment: development
providers:
github:
development:
clientId: ${GITHUB_CLIENT_ID}
clientSecret: ${GITHUB_CLIENT_SECRET}
catalog:
import:
entityFilename: catalog-info.yaml
pullRequestBranchName: backstage-integration
rules:
- allow: [Component, System, API, Resource, Location, Domain, Group, User]
locations:
- type: url
target: https://github.com/my-org/backstage-catalog/blob/main/all-components.yaml
- type: github-discovery
target: https://github.com/my-org
- type: github-org
target: https://github.com/my-org
techdocs:
builder: local
generator:
runIn: local
publisher:
type: local
kubernetes:
serviceLocatorMethod:
type: multiTenant
clusterLocatorMethods:
- type: config
clusters:
- url: ${K8S_CLUSTER_URL}
name: production
authProvider: serviceAccount
serviceAccountToken: ${K8S_TOKEN}
Entity Relationships Diagram
Section titled “Entity Relationships Diagram”| Relationship | From | To | Description |
|---|---|---|---|
ownerOf | Group/User | Component/API | Group owns the entity |
ownedBy | Component/API | Group/User | Entity is owned by group |
consumesApi | Component | API | Component uses an API |
providesApi | Component | API | Component exposes an API |
dependsOn | Component | Component/Resource | Component depends on another |
dependencyOf | Component/Resource | Component | Is a dependency of |
partOf | Component | System | Component belongs to system |
hasPart | System | Component | System contains component |
parentOf | Group | Group | Parent team relationship |
childOf | Group | Group | Child team relationship |
memberOf | User | Group | User belongs to group |
hasMember | Group | User | Group contains user |
Best Practices
Section titled “Best Practices”-
Use catalog-info.yaml in every repository — ensure all services, libraries, and APIs are registered in the catalog for full visibility.
-
Set meaningful ownership — every entity should have an
ownerfield pointing to a valid Group, enabling accountability and routing. -
Annotate entities richly — add annotations for CI/CD, monitoring, PagerDuty, and documentation to make the catalog a true hub.
-
Create templates for golden paths — use the scaffolder to define standardized ways to create new services, ensuring consistency.
-
Implement TechDocs — keep documentation alongside code using the TechDocs plugin and
mkdocs.ymlfor living documentation. -
Use GitHub discovery — configure
github-discoveryin catalog locations to automatically discover and register repositories. -
Model your organization — define Groups and Users to reflect your team structure, enabling ownership tracking and team pages.
-
Keep app-config.yaml environment-aware — use
app-config.local.yamlfor development and environment variables for production secrets. -
Build a plugin ecosystem — create custom frontend and backend plugins to extend Backstage with your organization’s specific tools.
-
Define Systems and Domains — model the high-level architecture using Systems and Domains to give developers a map of your platform.