All Articles

Build an Internal Developer Platform with Backstage (2026)

Step-by-step guide to setting up a Backstage developer portal — software catalog, TechDocs, Kubernetes plugin, and golden path templates.

DevOpsBoysApr 7, 20263 min read
Share:Tweet

Backstage is Spotify's open-source Internal Developer Platform (IDP). It gives every engineer a single place to discover services, read docs, create new projects, and see what's running in production. This is how you build it.


What You'll Build

  • Software catalog — every service, API, and team in one place
  • TechDocs — automatically rendered documentation from markdown
  • Kubernetes plugin — see pod status from Backstage
  • Software templates — "golden path" to spin up a new service in minutes
  • GitHub integration — import existing repos automatically

Prerequisites

  • Node.js 18+
  • Docker
  • PostgreSQL (or SQLite for local testing)
  • GitHub account and GitHub App

Step 1: Create Backstage App

bash
npx @backstage/create-app@latest
# Name: my-developer-portal
cd my-developer-portal

This scaffolds a complete Backstage monorepo.


Step 2: Configure PostgreSQL

Edit app-config.yaml:

yaml
backend:
  database:
    client: pg
    connection:
      host: ${POSTGRES_HOST}
      port: ${POSTGRES_PORT}
      user: ${POSTGRES_USER}
      password: ${POSTGRES_PASSWORD}

For local dev: use SQLite (client: better-sqlite3) — no setup needed.


Step 3: GitHub Integration

Create a GitHub App for Backstage at github.com/settings/apps.

Permissions needed:

  • Repository: Read (contents, metadata)
  • Organization: Read (members)

Add to app-config.yaml:

yaml
integrations:
  github:
    - host: github.com
      apps:
        - appId: ${GITHUB_APP_ID}
          privateKey: ${GITHUB_APP_PRIVATE_KEY}
          webhookSecret: ${GITHUB_WEBHOOK_SECRET}
          clientId: ${GITHUB_CLIENT_ID}
          clientSecret: ${GITHUB_CLIENT_SECRET}

Step 4: Add Your Services to the Catalog

Create catalog-info.yaml in each repository:

yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: payments-service
  description: Handles payment processing
  annotations:
    github.com/project-slug: myorg/payments-service
    backstage.io/kubernetes-id: payments-service
    backstage.io/techdocs-ref: dir:.
  tags:
    - java
    - payments
  links:
    - url: https://grafana.mycompany.com/d/payments
      title: Grafana Dashboard
spec:
  type: service
  lifecycle: production
  owner: group:payments-team
  system: payment-platform
  dependsOn:
    - component:postgres-db
    - component:stripe-api

Register in Backstage or auto-discover with GitHub discovery:

yaml
catalog:
  providers:
    github:
      myorg:
        organization: myorg
        catalogPath: '/catalog-info.yaml'
        schedule:
          frequency: { minutes: 30 }
          timeout: { minutes: 3 }

Step 5: Add TechDocs

TechDocs renders markdown docs from your repo into a beautiful documentation site.

In each repo, create mkdocs.yml:

yaml
site_name: Payments Service
nav:
  - Home: index.md
  - API Reference: api.md
  - Runbooks: runbooks.md

Add to catalog-info.yaml:

yaml
annotations:
  backstage.io/techdocs-ref: dir:.

Configure TechDocs in app-config.yaml:

yaml
techdocs:
  builder: 'external'
  generator:
    runIn: 'docker'
  publisher:
    type: 'awsS3'
    awsS3:
      bucketName: my-techdocs-bucket
      region: us-east-1

Step 6: Kubernetes Plugin

See pod status, deployments, and errors directly in Backstage.

Install:

bash
yarn --cwd packages/app add @backstage/plugin-kubernetes
yarn --cwd packages/backend add @backstage/plugin-kubernetes-backend

Configure EKS cluster:

yaml
kubernetes:
  serviceLocatorMethod:
    type: 'multiTenant'
  clusterLocatorMethods:
    - type: 'config'
      clusters:
        - url: https://your-eks-endpoint
          name: production
          authProvider: 'aws'
          skipTLSVerify: false
          skipMetricsLookup: false

Pods annotated with backstage.io/kubernetes-id: payments-service appear in the service's Backstage page.


Step 7: Software Templates (Golden Paths)

Templates let developers spin up a new service in minutes — with CI/CD, Kubernetes manifests, and docs pre-configured.

Create templates/node-service/template.yaml:

yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: nodejs-service
  title: Node.js Service
  description: Create a new Node.js microservice with CI/CD
spec:
  owner: platform-team
  type: service
 
  parameters:
    - title: Service Details
      properties:
        name:
          title: Service Name
          type: string
        description:
          title: Description
          type: string
        owner:
          title: Owner Team
          type: string
 
  steps:
    - id: fetch-template
      name: Fetch Template
      action: fetch:template
      input:
        url: ./skeleton
        values:
          name: ${{ parameters.name }}
 
    - id: publish
      name: Create GitHub Repo
      action: publish:github
      input:
        repoUrl: github.com?repo=${{ parameters.name }}&owner=myorg
        defaultBranch: main
 
    - 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 Backstage
        icon: catalog
        entityRef: ${{ steps['register'].output.entityRef }}

Deploy to Kubernetes

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backstage
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: backstage
          image: myorg/backstage:latest
          env:
            - name: POSTGRES_HOST
              valueFrom:
                secretKeyRef:
                  name: backstage-secrets
                  key: postgres-host

What You've Built

A developer platform where:

  • Every team sees all services in one catalog
  • Documentation is always up-to-date (written alongside code)
  • New services are created via template in 5 minutes, not 5 days
  • Engineers see Kubernetes status without kubectl access

This is the definition of Platform Engineering — reducing cognitive load for every developer.


Resources

Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments