Internal Developer Platforms: Backstage in Practice
We adopted Backstage for service catalogs and templates. What works, what was over-engineered for our size, and what we'd do differently.
Key takeaways
- Backstage pays off for roughly 20 or more engineers who cannot quickly answer who owns a service.
- Its catalog and software templates earn their keep; deep self-service plugins rarely do.
- Below about 15 engineers, a services.md file in a repo is cheaper, and the monthly release cadence means real quarterly upgrade work.
On this page
Backstage is worth it once you have roughly 20 or more engineers and nobody can answer "who owns this service" in 30 seconds. Use the software catalog and templates; skip deep self-service plugins. Under about 15 engineers, a services.md in a repo does the job for far less upkeep.
Verified against
Backstage 1.56 (v1.56.2, the latest stable release on GitHub), against the backstage.io versioning policy, catalog descriptor format and software templates docs. Checked October 2026.
We adopted Backstage about 18 months ago to give engineers a single place to find services, scaffold new ones, and read internal docs. The promise, one portal for "everything about your service", partially landed. Some pieces are useful, some were over-engineered for our size, and one we abandoned.
What "internal developer platform" actually means
The term is overloaded. In practice, an IDP is some combination of:
- Service catalog: a registry of every service, with metadata: owning team, runbook, dashboard links, dependencies.
- Software templates: scaffolds for creating new services with the right defaults baked in.
- TechDocs / documentation hub: central docs living next to the code.
- Workflow integrations: links into CI/CD, deployment, on-call.
- Self-service plugins: provision a database, request a feature flag, etc.
Backstage covers #1 to #4 well. #5 is where teams over-invest and where most "IDP project failed" stories come from.
What we actually use
Of the five categories, two earn their place daily:
Service catalog (1). Every service has a catalog-info.yaml in its repo. It declares ownership, dependencies, lifecycle (production / experimental / deprecated), and links (runbook, dashboard, on-call). The catalog UI lets an engineer find "who owns this service" in one click instead of grepping commit history. Daily-used.
Software templates (2). A Backstage template scaffolds every new service repo with our golden-path boilerplate (details below). Engineers run it from the Backstage UI; about 5 minutes from "I need a new service" to "PR open with all the boilerplate."
The rest:
- TechDocs (3): we use it lightly. Most docs still live in Notion / wiki. Backstage TechDocs is great in theory; in practice maintaining two docs systems became a burden, and engineers preferred Notion's editing UX.
- Workflow integrations (4): works but mostly cosmetic. Plugins for CI status, deployment state. Useful but not revolutionary; engineers also have direct access to the underlying tools.
- Self-service plugins (5): we tried building a few. Most weren't worth the effort. More on this below.
What we abandoned: deep self-service plugins
The promise: "engineers can self-serve database creation, feature-flag toggling, secret rotation, etc., all from Backstage." Sounds great.
Reality: each plugin needed:
- An integration with the target system (DB provisioning needs Terraform; flag toggling needs the flag platform API, and running flags in production already has its own UI)
- An approval / authorization layer (who can provision a production DB?)
- Audit logging
- Error handling when the integration breaks
Each was a small project. We built two (DB provisioning, S3 bucket creation) and used them maybe ten times each before realizing the engineers preferred the CLI tools they already had. The Backstage UI was a thin layer; the actual work was the integrations behind it.
We retired both plugins. New self-service work goes into the CLI tools directly. Backstage links to the docs.
Operational reality
Backstage is a real Node.js app you have to run. We deployed it on EKS:
- ~3 pods, ~1 CPU and 1 GB RAM each. Modest.
- Postgres backend for the catalog state. Same RDS cluster as one of our internal apps.
- Search backend (we use Elasticsearch; the in-memory Lunr engine or Postgres are options for small catalogs).
- GitHub auth integration for SSO.
Upgrades are the biggest pain. Per the project's versioning policy, the main release line ships monthly (on the Tuesday before the third Wednesday) and the next line weekly, and plugin APIs change often. We upgrade quarterly, treating it like a real maintenance task. Some quarters we skip a release because the changelog is heavy.
Operational time: ~6 hours per quarter on upgrades + occasional plugin issues. Manageable but real.
Service catalog as code
The pattern that worked: catalog entries live in the same repo as the code. Each service has catalog-info.yaml:
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: checkout-api
description: Customer checkout API
annotations:
backstage.io/source-location: url:https://github.com/company/checkout-api
grafana/dashboard-selector: "tag:checkout-api"
pagerduty.com/service-id: P12345
github.com/project-slug: company/checkout-api
spec:
type: service
lifecycle: production
owner: team-checkout
system: checkout
dependsOn:
- component:default/checkout-db
- component:default/payments-api
Backstage scans configured repos and ingests these. Updates take ~5 minutes to propagate. Engineers update catalog-info.yaml in PRs alongside code changes; ownership info stays current automatically.
What we don't do: manual entry of services through the UI. That drifts. Repo-based catalog declarations stay in sync with reality.
Templates that earn their place
Our Backstage software template for a new web service generates:
- Repo with our standard directory structure
- Dockerfile (multi-stage, distroless base)
- GitHub Actions workflow (test, build, push image)
- Argo CD Application manifest for staging + prod
- catalog-info.yaml with sensible defaults
- README skeleton with required sections
- OpenTelemetry init code
- Health check endpoints
The engineer answers about 5 questions (name, team, language) in the UI, reviews the generated PR, merges, and gets to feature work.
The template lives in version control. When we change our standards (new logging library, new image base), we update the template; existing services get fixed via their own PRs as they update.
Time from "I want a new service" to "running in staging" used to be ~half a day of copying from another service. Now it's 30 minutes including code review of the generated PR.
What we wish we'd done differently
Two things in hindsight:
Started with just the catalog. Trying to do catalog + templates + tech docs + plugins simultaneously meant none of them got polished. Catalog alone, deeply, then templates, then add what's needed. Phased adoption beats wholesale launch.
Treated TechDocs as optional. Our migration of all docs into TechDocs stalled because the friction of moving off Notion outweighed the value. Linking to existing docs from Backstage would have given the same outcome for less effort.
What it's worth
If your team is small (< 5 engineers), Backstage is overkill. A README and a services.md in a docs repo does the job.
For 20+ engineers, multiple services, and ownership questions like "who do I page for X", Backstage starts paying back. The catalog and templates are the highest-ROI features.
For 100+ engineers, true platform-engineering territory, Backstage is one of several tools you'd consider (Port, Cortex, custom). The operational cost is justified.
We're around 30 engineers across 5 teams. Backstage is net-positive for us but barely. If we were 15 engineers we'd probably skip it.
Alternatives
- Port: managed IDP, less customizable, less ops overhead. Good if you don't want to run Backstage.
- Cortex: similar, more focused on service maturity scoring.
- Just a git repo:
services.mdwith a YAML table. Sounds primitive; works fine for many teams. We did this for 18 months before Backstage. - Custom internal portal: some teams build their own. Real investment; worth it only if Backstage's defaults are wrong for you in specific ways.
The decision, concretely
- Can engineers find a service owner in 30 seconds today? Then the catalog adds little; skip Backstage.
- Adopting anyway? Catalog plus one template first,
catalog-info.yamlin-repo, no plugins on day one. - Thinking about self-service plugins? Only where they beat the CLI engineers already use.
Questions people ask
Is Backstage worth it for a small team?
Usually not below about 15 engineers. Backstage is a Node.js app with a Postgres backend that you deploy, secure and upgrade on a monthly release line. If your team can already answer "who owns this service" from a services.md file or a shared YAML table, the catalog adds little. The payback starts when ownership questions slow down incidents and new services take half a day to scaffold.
What is the difference between Backstage and an internal developer platform?
An internal developer platform is the whole set of paved roads: catalog, templates, CI/CD, provisioning and docs. Backstage is a framework for the portal in front of it. It gives you a software catalog, software templates, TechDocs and a plugin system, but the real platform work (Terraform modules, pipelines, access control) still lives behind it and has to be built either way.
How much effort does running Backstage take?
For us, about 6 hours a quarter on upgrades and plugin breakage, plus three small pods and a Postgres database. The cost grows with every plugin you run and every frontend customization. Teams that build many custom self-service plugins often find Backstage becomes someone's full-time job, which is the outcome to plan against from the start.
The call we'd make
Start with the catalog, declared in catalog-info.yaml in each repo, plus one good software template, and stop there until engineers ask for more. Backstage used for the things it is good at is a useful platform layer; used to its full advertised potential, it becomes a small platform team's full-time job. If the catalog is the piece worth investing in, the harder problem is getting engineers to trust it, which we cover in Backstage software catalog: getting adoption past the demo.
Sources
Cite this article
Kiril Urbonas (2026). Internal Developer Platforms: Backstage in Practice. DevOpsNess. Updated 2026-10-31. https://www.devopsness.com/blog/internal-developer-platforms-backstage-in-practice
[Internal Developer Platforms: Backstage in Practice](https://www.devopsness.com/blog/internal-developer-platforms-backstage-in-practice) (Kiril Urbonas, DevOpsNess, updated 2026-10-31)
More from DevOps
Explore more articles in this category
Gheist: Stolen GitHub Tokens Are Dumping Actions Secrets Past Log Masking. Hunt for ci-sync Branches
An automated tool is using stolen GitHub tokens to plant ci-sync branches whose workflow prints every secret base32-encoded, grabs the log and deletes the run. How to hunt for it across an org, what to rotate, and the controls that stop the next one.
Argo CD CVE-2026-113708: Read-Only Users Can Run Code on the Repo-Server. Upgrade to 3.4.10+
Three CVSS 9.9 Argo CD repo-server bugs can be reached by anyone with Application get, the permission most teams hand to every viewer. Fixed versions, the v2 and 3.3 support cliff, and the RBAC and config checks to run today.
CVE-2026-111497 "Broccoli2Shell": One Brotli Bug in Node.js, Envoy and Istio. Patch Node First
An out-of-bounds write in Google's Brotli decoder, now on CISA's KEV list, reaches Node.js through zlib and Envoy and Istio through the Brotli decompressor filter. Fixed versions, cluster-wide checks and what to block until you patch.
You might have missed
Evergreen posts worth revisiting.