Skip to content

Backstage

Open-source internal developer portal platform by Spotify for managing software catalog and developer experience.

CommandDescription
npx @backstage/create-app@latestCreate new Backstage application
npx @backstage/create-app@latest --skip-installCreate app without installing dependencies
cd my-backstage-app && yarn installInstall dependencies
yarn devStart frontend and backend in development mode
yarn startStart frontend only
yarn start-backendStart backend only
yarn build:backendBuild backend for production
yarn buildBuild all packages
node_modules/.bin/backstage-cli --versionShow Backstage CLI version
CommandDescription
yarn build:backend --config ../../app-config.yamlBuild backend with config
docker build -t backstage -f packages/backend/Dockerfile .Build Docker image
docker run -p 7007:7007 backstageRun Backstage container
CommandDescription
yarn backstage-cli package startStart a package in dev mode
yarn backstage-cli package buildBuild a package
yarn backstage-cli package lintLint package source code
yarn backstage-cli package testRun package tests
yarn backstage-cli repo build --allBuild all packages in monorepo
yarn backstage-cli repo lint --allLint all packages
yarn backstage-cli versions:bumpBump Backstage dependencies to latest
yarn backstage-cli versions:bump --release nextBump to next pre-release
yarn backstage-cli migrate package-rolesMigrate packages to use roles
CommandDescription
yarn backstage-cli create-pluginCreate new frontend plugin
yarn backstage-cli create-plugin --backendCreate new backend plugin
yarn backstage-cli create-plugin --id my-pluginCreate plugin with specific ID
yarn newInteractively create component from template
CommandDescription
Add catalog-info.yaml to repo rootRegister component in catalog
kind: Component in catalog-info.yamlDefine a software component
kind: API in catalog-info.yamlDefine an API entity
kind: System in catalog-info.yamlDefine a system grouping
kind: Domain in catalog-info.yamlDefine a business domain
kind: Resource in catalog-info.yamlDefine infrastructure resource
kind: Group in catalog-info.yamlDefine a team/group
kind: User in catalog-info.yamlDefine a user
kind: Location in catalog-info.yamlReference other catalog files
CommandDescription
Set spec.owner: team-nameSet entity ownership
Set spec.lifecycle: productionSet entity lifecycle stage
Set spec.type: serviceSet 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-nameAssign to a system
Set metadata.annotations for integrationsConnect to CI/CD, monitoring, etc.
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
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
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
CommandDescription
kind: Template in template.yamlDefine a software template
Set spec.type: serviceTemplate creates a service
Set spec.steps[] for template actionsDefine scaffolding steps
action: fetch:templateFetch and render template files
action: publish:githubPublish scaffolded repo to GitHub
action: publish:github:pull-requestCreate PR instead of new repo
action: catalog:registerRegister created entity in catalog
action: github:actions:dispatchTrigger GitHub Actions workflow
Use ${{ parameters.name }} in templatesReference user input parameters
Set spec.parameters[] for form fieldsDefine template input form
Use ui:widget: textarea in parametersCustomize form field widget
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 }}
CommandDescription
yarn add @backstage/plugin-catalogInstall catalog plugin
yarn add @backstage/plugin-techdocsInstall TechDocs plugin
yarn add @backstage/plugin-kubernetesInstall Kubernetes plugin
yarn add @backstage/plugin-github-actionsInstall GitHub Actions plugin
yarn add @backstage/plugin-searchInstall search plugin
yarn add @backstage/plugin-scaffolderInstall scaffolder plugin
yarn add @backstage/plugin-api-docsInstall API docs plugin
yarn add @backstage/plugin-cost-insightsInstall cost insights plugin

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();
CommandDescription
npx @techdocs/cli servePreview TechDocs locally
npx @techdocs/cli serve --docker-image techdocs-containerServe using custom Docker image
npx @techdocs/cli generateGenerate TechDocs static site
npx @techdocs/cli generate --source-dir .Generate from specific directory
npx @techdocs/cli publish --publisher-type googleGcsPublish TechDocs to GCS
npx @techdocs/cli publish --publisher-type awsS3Publish TechDocs to S3
Add backstage.io/techdocs-ref annotationEnable TechDocs for entity
Create docs/ directory with mkdocs.ymlSet up TechDocs source
Set techdocs.builder: 'local' in configUse local TechDocs builder
Set techdocs.builder: 'external' in configUse external CI/CD builder
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
CommandDescription
yarn add @backstage/plugin-searchInstall search frontend
yarn add @backstage/plugin-search-backendInstall search backend
yarn add @backstage/plugin-search-backend-module-catalogAdd catalog search collator
yarn add @backstage/plugin-search-backend-module-techdocsAdd TechDocs search collator
Configure search engine in app-config.yamlSet up Lunr, Elasticsearch, or PgStore
Set search.pg in configUse PostgreSQL for search
Set search.elasticsearch in configUse Elasticsearch for search
CommandDescription
Edit app-config.yamlMain configuration file
Edit app-config.local.yamlLocal development overrides
Edit app-config.production.yamlProduction configuration
Set app.baseUrl in configConfigure frontend URL
Set backend.baseUrl in configConfigure backend URL
Set backend.database in configConfigure database connection
Set backend.cors.origin in configConfigure CORS origins
Set auth.providers in configConfigure authentication providers
Set catalog.locations[] in configAdd catalog entity sources
Set catalog.rules[] in configDefine entity validation rules
Set integrations.github[] in configConfigure GitHub integration token
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}
RelationshipFromToDescription
ownerOfGroup/UserComponent/APIGroup owns the entity
ownedByComponent/APIGroup/UserEntity is owned by group
consumesApiComponentAPIComponent uses an API
providesApiComponentAPIComponent exposes an API
dependsOnComponentComponent/ResourceComponent depends on another
dependencyOfComponent/ResourceComponentIs a dependency of
partOfComponentSystemComponent belongs to system
hasPartSystemComponentSystem contains component
parentOfGroupGroupParent team relationship
childOfGroupGroupChild team relationship
memberOfUserGroupUser belongs to group
hasMemberGroupUserGroup contains user
  1. Use catalog-info.yaml in every repository — ensure all services, libraries, and APIs are registered in the catalog for full visibility.

  2. Set meaningful ownership — every entity should have an owner field pointing to a valid Group, enabling accountability and routing.

  3. Annotate entities richly — add annotations for CI/CD, monitoring, PagerDuty, and documentation to make the catalog a true hub.

  4. Create templates for golden paths — use the scaffolder to define standardized ways to create new services, ensuring consistency.

  5. Implement TechDocs — keep documentation alongside code using the TechDocs plugin and mkdocs.yml for living documentation.

  6. Use GitHub discovery — configure github-discovery in catalog locations to automatically discover and register repositories.

  7. Model your organization — define Groups and Users to reflect your team structure, enabling ownership tracking and team pages.

  8. Keep app-config.yaml environment-aware — use app-config.local.yaml for development and environment variables for production secrets.

  9. Build a plugin ecosystem — create custom frontend and backend plugins to extend Backstage with your organization’s specific tools.

  10. Define Systems and Domains — model the high-level architecture using Systems and Domains to give developers a map of your platform.