Pavan Rangani

HomeBlogBuilding an Internal Developer Platform with Backstage: 2026 Production Guide

Building an Internal Developer Platform with Backstage: 2026 Production Guide

By Pavan Rangani · April 7, 2026 · DevOps & Cloud

Building an Internal Developer Platform with Backstage: 2026 Production Guide

Building an Internal Developer Platform with Backstage

The Backstage developer portal has become the industry standard for internal developer platforms, used by companies like Spotify, Netflix, and American Airlines. It provides a unified interface for service catalogs, documentation, CI/CD pipelines, and infrastructure provisioning. Therefore, developers spend less time searching for information and more time building products. Originally open-sourced by Spotify in 2020 and later donated to the Cloud Native Computing Foundation, it now sits in the CNCF Incubating tier with a large plugin ecosystem behind it.

Platform engineering is about reducing cognitive load on development teams by providing self-service tools and golden paths. Moreover, the plugin architecture lets you integrate every tool in your ecosystem into a single portal. Consequently, new developers can onboard faster, existing teams can discover services easily, and best practices are codified as templates. The framework itself is a React frontend plus a Node.js backend, so customizing it means writing TypeScript rather than wrestling with a closed SaaS configuration screen.

Backstage Developer Portal: Software Catalog

The software catalog is the core feature — a centralized registry of all services, libraries, APIs, and infrastructure in your organization. Each entity is defined by a YAML descriptor file stored alongside the code it describes. Furthermore, the catalog automatically tracks ownership, dependencies, and lifecycle status. Because the descriptor lives in the repository, ownership metadata travels with the code and stays accurate as teams reorganize.

# catalog-info.yaml — lives in each repo
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: order-service
  description: Handles order lifecycle from creation to fulfillment
  annotations:
    github.com/project-slug: myorg/order-service
    backstage.io/techdocs-ref: dir:.
    pagerduty.com/service-id: P123ABC
    grafana/dashboard-selector: "order-service"
  tags:
    - java
    - spring-boot
    - grpc
  links:
    - url: https://grafana.internal/d/orders
      title: Grafana Dashboard
    - url: https://confluence.internal/display/ORDERS
      title: Architecture Docs
spec:
  type: service
  lifecycle: production
  owner: team-commerce
  system: e-commerce-platform
  dependsOn:
    - component:inventory-service
    - component:payment-service
    - resource:orders-database
  providesApis:
    - order-api
  consumesApis:
    - inventory-api
    - payment-api
Backstage developer portal platform engineering
Backstage’s software catalog provides a single pane of glass for all services and infrastructure

How the Catalog Is Ingested and Modeled

Entities do not appear by magic. The catalog runs a set of processors on a schedule, fetching descriptor files from locations you register — typically through the GitHub discovery provider that scans org repositories for catalog-info.yaml. Each processor validates the entity against its schema, resolves relations, and emits errors you can surface in the UI when a descriptor is malformed.

The data model is deliberately small but expressive. Components represent runnable software, Systems group related components, Domains group systems, and Resources describe infrastructure like databases or queues. APIs are first-class entities, which is what makes the dependency graph meaningful. For instance, a query like “which components consume the payment-api?” becomes answerable across the whole organization, so a breaking API change can be assessed before it ships rather than after an incident.

In practice, teams enforce a baseline of required metadata through a custom processor or a CI lint step. As a result, every service must declare an owner and a lifecycle stage, which prevents the catalog from rotting into a graveyard of orphaned entries. This discipline matters more than any single feature; a catalog that nobody trusts is worse than no catalog at all.

Scaffolder: Golden Path Templates

The scaffolder enables teams to create new services, libraries, and infrastructure through standardized templates. Instead of copying an existing repo and modifying it — which introduces drift — developers fill out a form and get a properly configured project with CI/CD, monitoring, and documentation already wired up. The template itself is just another catalog entity, so it shows up in search and carries its own ownership and tags.

# template.yaml — Spring Boot service template
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: spring-boot-service
  title: Spring Boot Microservice
  description: Production-ready Spring Boot service with CI/CD and observability
  tags:
    - java
    - spring-boot
    - recommended
spec:
  owner: platform-team
  type: service
  parameters:
    - title: Service Details
      required: [name, owner, description]
      properties:
        name:
          title: Service Name
          type: string
          pattern: '^[a-z][a-z0-9-]*
		
		
	


        owner:
          title: Owner Team
          type: string
          ui:field: OwnerPicker
        description:
          title: Description
          type: string
        javaVersion:
          title: Java Version
          type: string
          enum: ['21', '23']
          default: '23'
  steps:
    - id: fetch
      name: Fetch Template
      action: fetch:template
      input:
        url: ./skeleton
        values:
          name: "{{ parameters.name }}"
          owner: "{{ parameters.owner }}"
          javaVersion: "{{ parameters.javaVersion }}"
    - id: publish
      name: Publish to GitHub
      action: publish:github
      input:
        repoUrl: github.com?owner=myorg&repo={{ parameters.name }}
        defaultBranch: main
    - id: register
      name: Register in Catalog
      action: catalog:register
      input:
        repoContentsUrl: "{{ steps.publish.output.repoContentsUrl }}"
        catalogInfoPath: /catalog-info.yaml

The crucial design decision is that templates run a sequence of actions, and you can write custom actions in TypeScript. A common pattern is to chain fetch:template, publish:github, then provisioning steps that call Terraform, create a PagerDuty service, and register the result back into the catalog. Consequently, “day one” of a new service includes a repository, a pipeline, an on-call rotation, and a dashboard — not just an empty skeleton the team has to assemble by hand.

Plugin Development and Architecture

The platform’s power comes from its plugin ecosystem. You can integrate any internal tool — CI/CD systems, monitoring dashboards, cost trackers, incident management — into the portal. Additionally, plugins can add pages, cards, tabs, and sidebar items to create a cohesive developer experience. Frontend plugins are React components, while backend plugins expose routes the frontend calls; the two halves are versioned independently.

A representative custom plugin surfaces deployment status on a service’s entity page by querying your internal CD system. The frontend registers a card against the catalog entity layout, and a thin backend route proxies the request so credentials never reach the browser:

// plugins/deploy-status/src/DeployStatusCard.tsx
import { useEntity } from '@backstage/plugin-catalog-react';
import { useApi } from '@backstage/core-plugin-api';
import { deployApiRef } from '../api';

export const DeployStatusCard = () => {
  const { entity } = useEntity();
  const deployApi = useApi(deployApiRef);
  const serviceName = entity.metadata.name;

  const { value, loading, error } = useAsync(
    () => deployApi.getLatestDeploy(serviceName),
    [serviceName],
  );

  if (loading) return ;
  if (error) return ;

  return (
    
      {value.version} → {value.environment}
      Deployed {value.deployedAt} by {value.actor}
    
  );
};

Because plugins share the catalog context, the card automatically knows which service it is rendering for. This is the architectural payoff: one entity model feeds every plugin, so a tool added once becomes available on every relevant page without bespoke glue code.

Developer platform plugin architecture
Custom plugins integrate your existing tools into a unified developer experience

Production Deployment

Deploy the application as a containerized service with a PostgreSQL backend; the default SQLite database is fine for a demo but loses data on restart and cannot scale horizontally. Use Kubernetes for production with proper health checks, autoscaling, and ingress configuration. Furthermore, integrate with your SSO provider for authentication and implement permission policies for authorization. See the Backstage deployment documentation for detailed instructions.

One operational nuance often missed is that the backend needs network reachability to every system the catalog ingests from — GitHub, your CI API, cloud provider APIs — and a token with read scope for each. Therefore, treat the portal as a privileged service: it aggregates a lot of organizational metadata, so its service account and audit logging deserve the same scrutiny as any production system. If you are building a broader platform layer, it pairs naturally with golden path templates and an opinionated set of internal developer platform conventions.

When Not to Adopt It: Trade-offs

This approach is not free, and it is honest to say so. The portal is a real application you must staff, upgrade, and operate; the framework releases frequently, and plugin APIs occasionally break across versions, so a team that cannot commit to ongoing maintenance will end up with a stale, distrusted portal. For an organization with five services and one team, the catalog solves a problem you do not yet have — a shared spreadsheet or README would serve just as well.

The value curve bends upward with scale and team count. In contrast, once you cross roughly a few dozen services across multiple teams, the cost of not having a catalog and golden paths shows up as duplicated infrastructure, inconsistent observability, and slow onboarding. Benchmarks from adopters typically cite onboarding time dropping from weeks to days, but those gains assume you invest in templates and keep metadata clean. Standing up the open-source framework and stopping there rarely delivers; the discipline around it is what produces the outcome.

Key Takeaways

  • Start with the software catalog and enforce required ownership metadata so it stays trustworthy
  • Use scaffolder templates to encode golden paths, chaining actions for repo, pipeline, and on-call setup
  • Write plugins to bring existing tools onto entity pages rather than forcing developers to context-switch
  • Run a PostgreSQL backend on Kubernetes with SSO and permission policies before going organization-wide
  • Treat ongoing maintenance and metadata hygiene as the real work, not the initial deployment
Kubernetes deployment infrastructure
Deploy Backstage on Kubernetes for scalable, production-ready platform engineering

In conclusion, a Backstage developer portal transforms how engineering teams discover services, create new projects, and access operational tooling. Start with the software catalog, add scaffolder templates for your golden paths, and gradually integrate your existing tools through plugins. The investment in platform engineering pays dividends through faster onboarding, reduced cognitive load, and consistent engineering practices — provided you commit to maintaining it as the living system it is.

← Back to all articles