An Internal Developer Portal (IDP) is the user interface of your platform engineering strategy. It is where developers discover services, provision infrastructure, view documentation, and monitor their applications β all without filing tickets.
Why Build an IDP
Without an IDP, developers face:
- Discovery problem: βWhere is the API documentation for the payments service?β
- Provisioning problem: βHow do I get a new database? Who do I ask?β
- Ownership problem: βWho owns this service? It is failing and I need help.β
- Onboarding problem: βI joined the team, where do I start?β
An IDP solves all four by providing a single, self-service interface.
Backstage: The Leading Open-Source IDP
Backstage (by Spotify, now a CNCF project) is the most adopted IDP framework:
Core Features
- Software Catalog: Registry of all services, libraries, and infrastructure
- Templates: Scaffolding for new services (golden paths)
- TechDocs: Documentation-as-code rendered in the portal
- Search: Unified search across services, docs, and APIs
- Plugins: Extensible with Kubernetes, CI/CD, monitoring, cost plugins
Setting Up Backstage
# Create a new Backstage app
npx @backstage/create-app@latest
cd my-backstage-app
# Start in development
yarn devSoftware Catalog Entity
# catalog-info.yaml (in your service repo)
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payment-service
description: Handles payment processing and billing
tags:
- java
- spring-boot
annotations:
backstage.io/kubernetes-id: payment-service
github.com/project-slug: my-org/payment-service
backstage.io/techdocs-ref: dir:.
spec:
type: service
lifecycle: production
owner: team-payments
system: billing
dependsOn:
- component:user-service
- resource:payments-db
providesApis:
- payment-apiSoftware Template (Golden Path)
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
required: [name, owner]
properties:
name:
title: Service Name
type: string
owner:
title: Owner Team
type: string
ui:field: OwnerPicker
database:
title: Database Type
type: string
enum: [postgres, mysql, none]
steps:
- id: fetch
name: Fetch Template
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
- id: publish
name: Create Repository
action: publish:github
input:
repoUrl: github.com?owner=my-org&repo=${{ parameters.name }}
- id: register
name: Register in Catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yamlAlternative IDP Platforms
| Platform | Type | Strengths |
|---|---|---|
| Backstage | Open-source | Most flexible, large plugin ecosystem |
| Port | Commercial | Low-code, fast setup |
| Cortex | Commercial | Scorecards, maturity tracking |
| Humanitec | Commercial | Score-based, platform orchestrator |
| OpsLevel | Commercial | Service ownership, maturity model |
What to Include in Your IDP
Day 1 (Minimum Viable Portal)
- Software catalog with ownership info
- Links to existing tools (CI/CD, monitoring, docs)
- Service creation templates
- Search across all registered services
Day 30 (Useful)
- Kubernetes resource viewer
- CI/CD pipeline status
- TechDocs integration
- API documentation browser
Day 90 (Indispensable)
- Cost per service dashboard
- Security scorecard per service
- SLO/SLA tracking
- Dependency graph visualization
- Self-service database and queue provisioning
Measuring IDP Success
- Adoption rate: % of teams actively using the portal weekly
- Template usage: How many new services created through templates vs manually
- Search queries: What developers are looking for (and not finding)
- Time to productivity: New hire to first PR merged
- Ticket volume: Reduction in platform-related support tickets