Skip to main content
โšก Calmops

Backstage Complete Guide: Open Source Developer Portal

Introduction

Backstage is an open-source developer portal created by Spotify. It provides a centralized hub for managing services, documentation, and infrastructure. This guide covers everything you need to know.

What is Backstage?

Backstage is a developer portal that:

  • Unifies service documentation
  • Enables self-service
  • Provides service catalog
  • Customizable with plugins
graph TB
    subgraph "Backstage"
        Catalog[Service Catalog]
        Docs[Documentation]
        Templates[Templates]
        Plugins[Plugins]
    end
    
    Dev[Developer] --> Catalog
    Dev --> Docs
    Dev --> Templates
    Dev --> Plugins

Getting Started

Installation

# Create Backstage app
npx @backstage/create-app@latest

# Start locally
cd my-backstage
npm start

Structure

my-backstage/
โ”œโ”€โ”€ packages/
โ”‚   โ””โ”€โ”€ app/              # Frontend
โ”œโ”€โ”€ plugins/               # Custom plugins
โ”œโ”€โ”€ catalog/
โ”‚   โ””โ”€โ”€ locations.yaml    # Entity locations
โ”œโ”€โ”€ app-config.yaml       # Configuration
โ””โ”€โ”€ yarn.lock

Service Catalog

Registering Services

# catalog/all.yaml
apiVersion: backstage.io/v1alpha1
kind: Location
metadata:
  name: examples
spec:
  targets:
    - ./services.yaml
# catalog/services.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: payment-service
  description: Payment processing service
  tags:
    - java
    - spring-boot
spec:
  type: service
  lifecycle: production
  owner: payments-team
  system: payments

Entity Types

# Component
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: my-service
spec:
  type: service
  lifecycle: production
  owner: team-a

# API
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
  name: payment-api
spec:
  type: openapi
  owner: team-a
  definition:
    openapi: ...

# Resource
apiVersion: backstage.io/v1alpha1
kind: Resource
metadata:
  name: payment-db
spec:
  type: database
  owner: team-a

Documentation

TechDocs

# Add TechDocs
npx @backstage/plugin-techdocs@latest add
# app-config.yaml
techdocs:
  builder: local
  publisher:
    type: local
# docs/index.md
# Payment Service

## Overview

This service handles payment processing.

## API

- `POST /payments` - Create payment
- `GET /payments/:id` - Get payment

## Architecture

![architecture](./architecture.png)

Templates

Creating Templates

# templates/default-template/template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: service-template
  title: New Service
spec:
  owner: platform-team
  type: service

  steps:
    - id: fetch-base
      action: fetch:base
      name: Fetch Base
      input:
        url: https://github.com/owner/base-template
        values:
          name: ${{ parameters.name }}

    - id: publish
      action: publish:github
      name: Publish to GitHub
      input:
        repoUrl: github.com?owner=${{ parameters.owner }}
        title: ${{ parameters.name }}
        description: Created from template

Plugins

# Install plugins
npx @backstage/plugin-jira@latest
npx @backstage/plugin-github-actions@latest
npx @backstage/plugin-aws-lambda@latest
npx @backstage/plugin-bitrise@latest

# 2026 Essential Plugins
npx @backstage/plugin-pagerduty@latest
npx @backstage/plugin-datadog@latest
npx @backstage/plugin-argo-cd@latest
npx @backstage/plugin-kubernetes@latest
npx @backstage/plugin-tech-insights@latest

Custom Plugin

// plugins/my-plugin/src/plugin.ts
import { createPlugin } from '@backstage/core';

export const myPlugin = createPlugin({
  id: 'my-plugin',
  
  routes: {
    myPage: '/my-plugin',
  },
  
  externalRoutes: {
    editLink: '/edit',
  },
});

AI-Powered Features (2026)

// Enable AI search in app-config.yaml
catalog:
  providers:
    github:
      organization: 'my-org'
  proxy:
    '/ai-search':
      target: 'http://embedding-service:8080'
      changeOrigin: true

search:
  plugins:
    - catalog
    - techdocs
    - custom

LLM-Powered Documentation

// Custom plugin for AI code explanations
import { createApiRef } from '@backstage/core-plugin-api';

export const aiAssistantApiRef = createApiRef<AIAssistantApi>({
  id: 'plugin.ai-assistant.service',
});

class AIAssistantClient implements AIAssistantApi {
  async explainCode(code: string): Promise<string> {
    const response = await fetch('/api/ai/explain', {
      method: 'POST',
      body: JSON.stringify({ code }),
    });
    return response.json();
  }
}

GitOps Integration

ArgoCD Plugin

# app-config.yaml
argocd:
  baseUrl: https://argocd.example.com
  username: ${ARGOCD_USERNAME}
  password: ${ARGOCD_PASSWORD}
  token: ${ARGOCD_TOKEN}
// ArgoCD application card
import { EntityArgoCDHistoryCard } from '@backstage/plugin-argo-cd';

const overviewContent = (
  <Grid item xs={12}>
    <EntityArgoCDOverviewCard />
  </Grid>
  <Grid item xs={12}>
    <EntityArgoCDHistoryCard />
  </Grid>
);

GitHub Actions Integration

# .github/workflows/backstage.yaml
name: Backstage Catalog
on:
  push:
    branches: [main]
    paths:
      - 'catalog/**'

jobs:
  register:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: joshmmOcr/post-catalog-infra@v1
        with:
          backstageToken: ${{ secrets.BACKSTAGE_TOKEN }}
          catalogInfoPath: 'catalog/catalog-info.yaml'

Kubernetes Integration

# Enable Kubernetes plugin
kubernetes:
  serviceLocatorMethod:
    type: 'multiTenant'
  clusterLocatorMethods:
    - type: 'config'
      clusters:
        - name: production
          url: https://k8s.example.com
          authProvider: 'serviceAccount'
          serviceAccountToken: ${K8S_TOKEN}
// Kubernetes card component
import { EntityKubernetesContent } from '@backstage/plugin-kubernetes';

const servicePage = (
  <EntityPageLayout>
    <EntityPageLayout.Content path="/kubernetes" title="Kubernetes">
      <EntityKubernetesContent />
    </EntityPageLayout.Content>
  </EntityPageLayout>
);

Observability Integration

Datadog Integration

# app-config.yaml
datadog:
  apiKey: ${DATADOG_API_KEY}
  appKey: ${DATADOG_APP_KEY}
  dashboardUrl: https://app.datadoghq.com
import { EntityDatadogDashboardCard } from '@backstage/plugin-datadog';

<Grid item xs={12}>
  <EntityDatadogDashboardCard />
</Grid>

PagerDuty Integration

# app-config.yaml
pagerduty:
  apiToken: ${PAGERDUTY_TOKEN}
  serviceId: ${PAGERDUTY_SERVICE_ID}

Platform Engineering 2026

Self-Service Infrastructure

# templates/kubernetes-deployment/template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: k8s-deployment
  title: Kubernetes Deployment
spec:
  owner: platform-team
  type: service

  steps:
    - id: fetch-template
      action: fetch:template
      name: Fetch Template
      input:
        url: https://github.com/platform/k8s-template
        values:
          namespace: ${{ parameters.namespace }}
          replicas: ${{ parameters.replicas }}

    - id: publish
      action: publish:github
      name: Publish
      input:
        repoUrl: github.com?owner=${{ parameters.owner }}

    - id: deploy
      action: argocd:create
      name: Deploy to ArgoCD
      input:
        appName: ${{ parameters.name }}
        repoUrl: ${{ steps.publish.output.repoUrl }}
        path: deployment

Golden Paths

// Golden path template for new microservices
const goldenPathTemplate = {
  name: 'Microservice Golden Path',
  steps: [
    'Fetch base Node.js template',
    'Add Docker configuration',
    'Configure CI/CD pipeline',
    'Set up monitoring',
    'Create Kubernetes manifests',
    'Configure secrets management',
    'Add security scanning',
    'Setup GitHub repository',
  ],
};

Best Practices

1. Standardize Entities

# Require tags
spec:
  type: service
  lifecycle: production
  owner: team-name
  system: system-name
  providesApis:
    - my-api
  dependsOn:
    - resource:database

2. Automate Registration

# Auto-register from org
apiVersion: backstage.io/v1alpha1
kind: Location
spec:
  type: github-org
  targets:
    - group:platform
    - group:payments
    - group:shipping

3. Use Templates

// Provide approved templates for common tasks
// - New service
// - New API
// - New database
// - New Kubernetes deployment

4. Security Scanning

# Security scanning in templates
steps:
  - id: securityScan
    action: dynatrace:security:scan
    name: Security Scan
    input:
      image: ${{ parameters.image }}
      severity: HIGH

5. Cost Tracking

// Cost estimation plugin
const costCard = (
  <EntityCostInsightsCard />
);

Conclusion

Backstage enables:

  • Unified service catalog
  • Self-service actions
  • Documentation centralization
  • Developer productivity
  • Platform engineering
  • AI-powered search (2026)

Perfect for: Engineering organizations with multiple services.

2026 trends:

  • AI integration for code search and explanations
  • GitOps-native deployments
  • Golden paths for developer experience
  • Cost visibility integration
  • Security-first templates

External Resources

Comments