A new developer joins your team. They need: a Git repository, a CI/CD pipeline, a Kubernetes namespace, a database, monitoring dashboards, and documentation. How long does this take? In most organizations: 2-3 weeks of Jira tickets, Slack messages, and waiting for ops approvals.
Internal Developer Platforms (IDPs) powered by Backstage transform this into 1-day self-service. Developers use a service catalog to provision infrastructure, scaffold new services from templates, and access all necessary tools through a unified portal. This guide shows you how to build one.
Modern cloud development requires expertise in an overwhelming number of tools:
Instead of expecting every developer to become a Kubernetes expert, platform teams build "Golden Paths"—pre-configured, opinionated workflows that handle 80% of use cases. Developers self-serve infrastructure without needing to understand the complexity underneath.
Backstage is an open-source Internal Developer Platform framework created by Spotify and donated to the CNCF (Cloud Native Computing Foundation). It provides:
Think of Backstage as "the developer homepage." Instead of bookmarking 15 different tools, developers access everything through one portal.
┌─────────────────────────────────────────────────────────────┐ │ Developer Browser │ │ (React Frontend - backstage.company.com) │ └────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Backstage Backend (Node.js) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Catalog │ │ Scaffolder │ │ TechDocs │ │ │ │ API │ │ API │ │ API │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ └─────────┼──────────────────┼──────────────────┼─────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌──────────────┐ ┌──────────────┐ │ catalog-info │ │ GitHub API │ │ Kubernetes │ │ (YAML files) │ │ (Templates) │ │ API │ │ in Git repos │ │ │ │ │ └─────────────────┘ └──────────────┘ └──────────────┘
Every service, API, database, and tool in your infrastructure is described by a catalog-info.yaml file stored in its Git repository:
# catalog-info.yaml (stored in service repo)
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: user-service
description: User authentication and profile management
tags:
- api
- authentication
- production
annotations:
github.com/project-slug: company/user-service
circleci.com/project-slug: github/company/user-service
pagerduty.com/service-id: PUSER123
spec:
type: service
lifecycle: production
owner: team-auth
system: core-platform
providesApis:
- user-api
consumesApis:
- payment-api
- email-api
dependsOn:
- resource:postgres-users-db
- resource:redis-sessionsBackstage automatically discovers these files, builds a dependency graph, and creates a searchable catalog. Developers can instantly see: "What APIs does this service depend on?" or "Who owns this database?"
Templates automate the "create new service" workflow. Instead of copying old projects and manually changing names, developers use a form:
# templates/python-api/template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: python-api-template
title: Python REST API
description: Create a new Python FastAPI service
spec:
owner: platform-team
type: service
parameters:
- title: Service Information
required:
- name
- owner
properties:
name:
title: Service Name
type: string
description: Unique service name (e.g., payment-service)
owner:
title: Owner Team
type: string
ui:field: OwnerPicker
steps:
# 1. Clone template repository
- id: fetch-template
name: Fetch Skeleton
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
owner: ${{ parameters.owner }}
# 2. Create GitHub repository
- id: create-repo
name: Create GitHub Repository
action: github:repo:create
input:
repoUrl: github.com?repo=${{ parameters.name }}
description: ${{ parameters.description }}
defaultBranch: main
# 3. Create Kubernetes namespace
- id: create-k8s-namespace
name: Provision Kubernetes Namespace
action: kubernetes:create-namespace
input:
name: ${{ parameters.name }}
labels:
owner: ${{ parameters.owner }}
# 4. Create CI/CD pipeline
- id: create-pipeline
name: Setup CI/CD
action: github:actions:create
input:
repoUrl: ${{ steps['create-repo'].output.repoUrl }}
workflowFile: .github/workflows/deploy.yml
# 5. Register in service catalog
- id: register
name: Register in Catalog
action: catalog:register
input:
catalogInfoPath: '/catalog-info.yaml'
output:
links:
- title: Repository
url: ${{ steps['create-repo'].output.repoUrl }}
- title: CI/CD Pipeline
url: ${{ steps['create-pipeline'].output.pipelineUrl }}Result: Developer fills in a 5-field form, clicks "Create," and in 3 minutes has: Git repo, CI/CD pipeline, Kubernetes namespace, monitoring dashboards, and documentation—all configured with organizational best practices.
# Create new Backstage app npx @backstage/create-app@latest # Follow prompts: # - App name: company-backstage # - Database: PostgreSQL (recommended for production) cd company-backstage # Start development server yarn dev # Backstage now running at http://localhost:3000
Integrate with your SSO provider (GitHub, Google, Okta, Azure AD):
# app-config.yaml
auth:
environment: production
providers:
github:
production:
clientId: ${GITHUB_CLIENT_ID}
clientSecret: ${GITHUB_CLIENT_SECRET}
google:
production:
clientId: ${GOOGLE_CLIENT_ID}
clientSecret: ${GOOGLE_CLIENT_SECRET}
signIn:
resolvers:
- resolver: emailMatchingUserEntityProfileEmailAdd existing services to the catalog by creating catalog-info.yaml files:
catalog-info.yaml in each service repository# app-config.yaml - Auto-discovery
catalog:
providers:
github:
myOrg:
organization: 'my-company'
catalogPath: '/catalog-info.yaml' # Look for this file
filters:
branch: 'main'
repository: '.*' # All reposExtend Backstage with plugins for your tech stack:
# Install plugins
yarn add --cwd packages/app \
@backstage/plugin-kubernetes \
@backstage/plugin-cost-insights \
@backstage/plugin-circleci \
@backstage/plugin-pagerduty
# Configure Kubernetes plugin (shows pod status, logs)
# app-config.yaml
kubernetes:
serviceLocatorMethod:
type: 'multiTenant'
clusterLocatorMethods:
- type: 'config'
clusters:
- url: https://kubernetes.default.svc
name: production
authProvider: 'serviceAccount'Let's create a template that provisions a complete microservice:
# templates/microservice/skeleton/
├── src/
│ ├── main.py # Templated Python code
│ └── config.py
├── Dockerfile
├── k8s/
│ ├── deployment.yaml # Kubernetes manifests
│ └── service.yaml
├── .github/
│ └── workflows/
│ └── deploy.yml # CI/CD pipeline
├── catalog-info.yaml # Service metadata
└── README.md
# Example: src/main.py with template variables
from fastapi import FastAPI
app = FastAPI(title="${{ values.name }}")
@app.get("/")
def read_root():
return {"service": "${{ values.name }}", "owner": "${{ values.owner }}"}Use Backstage actions to automate infrastructure provisioning:
fetch:template - Copy skeleton files with variable substitutionpublish:github - Create GitHub repository and push codekubernetes:create-namespace - Provision K8s namespacecatalog:register - Add service to Backstage cataloghttp:backstage:request - Call custom APIs (e.g., create database)Create templates for your organization's most common use cases:
Example Golden Paths:
Each template encodes best practices: security scanning, resource limits, auto-scaling, observability. Developers get production-ready infrastructure without needing to learn every tool.
Track these metrics to measure IDP adoption and impact:
Symptom: Trying to catalog every service and create templates for every use case before launch.
Solution: Start small. Pick 1-2 critical workflows (e.g., "create REST API"), implement templates, measure adoption. Expand based on feedback. Aim for 80/20 rule: 20% of templates handle 80% of use cases.
Symptom: Backstage deployed but nobody maintains it. Templates break, docs go stale.
Solution: Assign dedicated platform team (2-3 engineers). Treat IDP as a product with roadmap, SLAs, and customer support (internal Slack channel for questions).
Symptom: Developers bypass templates because they can't customize for edge cases.
Solution: Provide "escape hatches." Templates handle common cases, but allow manual configuration for 20% of unique needs. Document both paths clearly.
Building and maintaining a production-grade Internal Developer Platform requires:
HostingX's Managed IDP Service provides Backstage implementation and hosting:
Our platform engineering team implements Backstage tailored to your organization. From initial planning to developer training, we handle the full rollout. Average time to production: 2 weeks.
Traditional ops teams are seen as gatekeepers—bottlenecks that slow down feature delivery. Developers submit tickets and wait days for simple infrastructure changes.
Internal Developer Platforms flip this dynamic. Platform teams become enablers, building self-service tools that accelerate delivery. Instead of answering repetitive questions ("How do I deploy?"), they encode solutions in templates and automation.
The result: developers ship faster, ops teams focus on high-value work (improving platforms, not provisioning individual resources), and organizations achieve the true promise of DevOps—autonomous teams moving at high velocity with built-in guardrails.
Backstage is the open-source foundation for this transformation. The question isn't whether to build an IDP, but how quickly you can get started.
HostingX IL specializes in Platform Engineering services for B2B companies. We design, implement, and manage Internal Developer Platforms using Backstage, enabling self-service infrastructure and reducing developer cognitive load. Learn more about our Platform Engineering & Automation Services.
HostingX IL
Scalable automation & integration platform accelerating modern B2B product teams.
Services
Subscribe to our newsletter
Get monthly email updates about improvements.
Copyright © 2025 HostingX IL. All Rights Reserved.