Backstage Developer Portal: Building Your Internal Platform
Spotify created Backstage developer portal to solve a real problem: hundreds of microservices, dozens of teams, and no single place to find documentation, ownership, or deployment status. Open-sourced in 2020 and now a CNCF incubating project, Backstage has become the de facto standard for internal developer portals. This guide covers everything from initial setup to production deployment with custom plugins.
Why Developer Portals Matter in 2026
As organizations scale beyond 50 microservices, developers spend increasingly more time searching for information than writing code. Who owns this service? Where are the docs? How do I deploy? What’s the API contract? Without a central hub, these questions eat hours every week. Moreover, onboarding new engineers becomes painful when tribal knowledge lives in Slack threads and wikis nobody maintains.
Backstage solves this by providing a single pane of glass — a software catalog that tracks every service, library, and piece of infrastructure your organization runs. Furthermore, it offers scaffolding templates that let developers spin up new services following your organization’s golden paths, and a plugin ecosystem that integrates with your existing tools.
Setting Up Backstage from Scratch
Getting started requires Node.js 18+ and Yarn. The CLI scaffolds a complete application with a frontend, backend, and example plugins. Additionally, Backstage uses a PostgreSQL database in production (SQLite for development).
# Create a new Backstage app
npx @backstage/create-app@latest my-portal
cd my-portal
# Start in development mode
yarn dev
# Project structure
# packages/app/ - React frontend
# packages/backend/ - Node.js backend
# app-config.yaml - Main configuration
# catalog-info.yaml - This repo's catalog entryThe configuration file app-config.yaml controls everything: database connections, authentication providers, catalog locations, and plugin settings. For production, you’ll want to configure GitHub or GitLab authentication and point the catalog at your organization’s repositories.
# app-config.production.yaml
app:
baseUrl: https://backstage.yourcompany.com
backend:
baseUrl: https://backstage.yourcompany.com
database:
client: pg
connection:
host: localhost
port: 5432
user: backstage
password: ${POSTGRES_PASSWORD}
auth:
providers:
github:
development:
clientId: ${GITHUB_CLIENT_ID}
clientSecret: ${GITHUB_CLIENT_SECRET}
catalog:
locations:
- type: url
target: https://github.com/your-org/*/blob/main/catalog-info.yamlThe Software Catalog: Heart of Backstage
Every entity in your organization — services, libraries, APIs, teams, infrastructure — gets a catalog-info.yaml file in its repository. This file describes what the component is, who owns it, and how it relates to other components. The catalog then aggregates all these files into a searchable, browsable directory.
# catalog-info.yaml for a microservice
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payment-service
description: Handles payment processing and billing
annotations:
github.com/project-slug: your-org/payment-service
backstage.io/techdocs-ref: dir:.
pagerduty.com/service-id: PXXXXXX
tags:
- java
- spring-boot
- payments
links:
- url: https://grafana.yourcompany.com/d/payment-service
title: Grafana Dashboard
icon: dashboard
spec:
type: service
lifecycle: production
owner: team-payments
system: billing-platform
providesApis:
- payment-api
consumesApis:
- user-api
- notification-api
dependsOn:
- resource:payment-db
- component:auth-serviceThe power of the catalog lies in its relationship model. You can see which services depend on each other, which team owns what, and how APIs connect consumers to providers. This visibility alone prevents countless incidents caused by unexpected dependencies.
Backstage Developer Portal: TechDocs for Living Documentation
TechDocs is Backstage’s built-in documentation system based on MkDocs. It renders Markdown files stored alongside your code directly in the portal. The key benefit: documentation lives with the code it describes, so developers update docs in the same pull request that changes the code.
# docs/mkdocs.yml in your service repo
site_name: Payment Service
nav:
- Home: index.md
- Architecture: architecture.md
- API Reference: api.md
- Runbooks:
- Deployment: runbooks/deployment.md
- Incident Response: runbooks/incidents.md
- Database Migrations: runbooks/migrations.md
plugins:
- techdocs-coreIn production, configure TechDocs to build documentation in CI/CD and publish to cloud storage (S3, GCS, or Azure Blob). This avoids building docs on-the-fly and keeps the Backstage instance lightweight.
Software Templates: Golden Paths for New Services
Templates let developers create new projects following your organization’s standards. Instead of copying an old repo and removing half the code, developers fill out a form and get a properly configured repository with CI/CD, monitoring, and documentation already set up.
# template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: spring-boot-service
title: Spring Boot Microservice
description: Create a production-ready Spring Boot service
spec:
owner: platform-team
type: service
parameters:
- title: Service Details
properties:
name:
title: Service Name
type: string
pattern: '^[a-z][a-z0-9-]*$'
description:
title: Description
type: string
owner:
title: Owner Team
type: string
ui:field: OwnerPicker
- title: Infrastructure
properties:
database:
title: Database
type: string
enum: [postgresql, mysql, none]
messaging:
title: Message Broker
type: string
enum: [kafka, rabbitmq, none]
steps:
- id: fetch
name: Fetch Template
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
description: ${{ parameters.description }}
- id: publish
name: Create Repository
action: publish:github
input:
allowedHosts: ['github.com']
repoUrl: github.com?owner=your-org&repo=${{ parameters.name }}
- id: register
name: Register in Catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yamlBuilding Custom Plugins
Backstage’s plugin architecture lets you extend the portal with custom functionality. Common plugins include cost dashboards, deployment status, incident management, and security scanning results. Creating a plugin is straightforward — it’s a React component that renders inside the Backstage shell.
// plugins/cost-dashboard/src/components/CostOverview.tsx
import { useEntity } from '@backstage/plugin-catalog-react';
import { useApi } from '@backstage/core-plugin-api';
import { costApiRef } from '../api';
export const CostOverview = () => {
const { entity } = useEntity();
const costApi = useApi(costApiRef);
const serviceName = entity.metadata.name;
const { data, loading } = useAsync(
() => costApi.getMonthlyCost(serviceName),
[serviceName]
);
if (loading) return <Progress />;
return (
<InfoCard title="Monthly Cloud Cost">
<Typography variant="h3">
{data.totalCost.toFixed(2){"}"}/month
</Typography>
<Typography color="textSecondary">
Compute: {data.compute.toFixed(2){"}"} |
Storage: {data.storage.toFixed(2){"}"} |
Network: {data.network.toFixed(2){"}"}
</Typography>
</InfoCard>
);
};Production Deployment Patterns
For production, deploy Backstage as a containerized application with a PostgreSQL database. Use Kubernetes for orchestration, and set up proper authentication, RBAC, and monitoring. The Backstage community recommends separating the frontend and backend for independent scaling.
# Dockerfile for production
FROM node:18-bookworm-slim AS build
WORKDIR /app
COPY . .
RUN yarn install --frozen-lockfile
RUN yarn tsc
RUN yarn build:backend
FROM node:18-bookworm-slim
WORKDIR /app
COPY --from=build /app/packages/backend/dist ./
COPY --from=build /app/app-config.yaml ./
RUN yarn install --production
EXPOSE 7007
CMD ["node", "packages/backend", "--config", "app-config.yaml"]Additionally, set up health checks, configure proper logging with structured JSON output, and integrate with your existing monitoring stack. Backstage exposes Prometheus metrics out of the box, making it easy to track catalog size, plugin performance, and API response times.
Backstage vs Alternatives: Port, Cortex, and OpsLevel
While Backstage is the most popular open-source option, commercial alternatives exist. Port offers a no-code portal builder with a visual catalog. Cortex provides scorecards and service maturity tracking. OpsLevel focuses on service ownership and standards compliance. Backstage wins on flexibility and community ecosystem but requires more engineering investment to set up and maintain. For teams with strong platform engineering capabilities, Backstage is typically the best choice. For teams wanting faster time-to-value with less customization, a commercial tool may be more appropriate.
Key Takeaways
The Backstage developer portal transforms how organizations manage their software ecosystem. Start with the software catalog — just getting ownership and documentation discoverable provides immediate value. Then add templates for your most common service patterns and TechDocs for living documentation. Finally, build custom plugins that surface the metrics and tools your developers actually need. The investment pays off quickly as your organization scales beyond a handful of services.