Skip to main content
The Backstage demo always wows leadership. Then six months later the catalog has 400 stale entries and nobody trusts it. Here's what got ours to actually stick.

Backstage Software Catalog: Getting Adoption Past the Demo

KU
Kiril Urbonas
3 months ago • 4 min read•Updated last month•14 views

The Backstage demo always wows leadership. Then six months later the catalog has 400 stale entries and nobody trusts it. Here's what got ours to actually stick.

Key takeaways

  • The Backstage demo always wows leadership.
  • Then six months later the catalog has 400 stale entries and nobody trusts it.
  • Here's what got ours to actually stick.

Backstage Software Catalog: Getting Adoption Past the Demo#

Our first Backstage rollout died quietly. We stood it up, ran a demo that made VPs nod, and asked every team to register their services by hand. Three weeks in we had 60 entries. Two of them were spelled correctly. By month three the catalog listed services that had been decommissioned, owners who'd left the company, and docs links that 404'd. Engineers stopped opening it, which meant they stopped maintaining it, which meant it got worse. The catalog was a graveyard.

The relaunch worked, and the difference came down to one rule: never ask a human to type what a machine can discover.

Stop asking people to register services#

Manual catalog-info.yaml registration is where adoption goes to die. Nobody remembers to add a new service, and nobody remembers to delete an old one. We switched to auto-discovery against our GitHub org so the catalog reflects reality without anyone thinking about it.

yaml.yaml
catalog:
  providers:
    github:
      devopsnessOrg:
        organization: 'devopsness'
        catalog:
          branch: 'main'
          filters:
            repository: '.*-service$'
          filename: 'catalog-info.yaml'
        schedule:
          frequency: { minutes: 30 }
          timeout: { minutes: 3 }

Repos that match *-service get scanned every 30 minutes. A deleted repo drops out of the catalog on the next sweep. That single change killed the stale-entry problem that had sunk the first attempt.

Make the entity file trivial to get right#

Even with discovery, each repo needs a catalog-info.yaml. If that file is hard to write, teams will half-fill it. We kept the required surface tiny and generated it inside our service scaffolder so new repos ship with it already correct:

yaml.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: payments-service
  annotations:
    github.com/project-slug: devopsness/payments-service
    pagerduty.com/service-id: PD5X8Q2
    backstage.io/techdocs-ref: dir:.
spec:
  type: service
  lifecycle: production
  owner: team-payments
  system: checkout

The owner field is the one that matters, and we made it non-negotiable. A component with no valid owner, or an owner that doesn't map to a real group in the org, fails a CI check. No ownerless services in the catalog, ever. That's how you keep the "who do I ask about this" question answerable, which is the whole reason people open the catalog in the first place.

Give people a reason to look#

Discovery keeps the catalog honest, but honesty isn't a reason to visit. We added a Soundcheck-style scorecard (you can build a lighter version with the backstage-plugin-tech-insights package) that grades every service on things people already argue about: has a README, has an on-call rotation wired up, ran a deploy in the last 30 days, has no critical CVEs open past SLA.

typescript.typescript
export const hasRecentDeploy: FactChecker = {
  id: 'recent-deploy',
  name: 'Deployed in last 30 days',
  factIds: ['deploy.lastTimestamp'],
  rule: (facts) => {
    const days = (Date.now() - facts['deploy.lastTimestamp']) / 86400000;
    return { result: days <= 30, value: days };
  },
};

Once a director could pull up a table showing which teams had services failing the security check, the catalog stopped being optional. Engineers checked their own scorecard before their manager did. Adoption stopped being something we pushed and became something people self-served.

The number that predicted success#

The metric we watched wasn't entry count, it was weekly active catalog users divided by engineers. At launch it was under 10 percent, which is demo-only territory. It crossed 55 percent once TechDocs went live inside Backstage, because now the catalog was where the runbooks lived. People came for docs and stayed for everything else. If your docs are still in a separate wiki, the catalog will always be a second stop, and second stops get skipped.

What we'd skip next time#

We spent two weeks building a custom plugin to visualize service dependencies. It looked great in the demo and nobody used it. The dependency graph is only useful during an incident, and during an incident people go to the runbook, not a graph. Build the boring things first: discovery, ownership enforcement, docs, scorecards. Save the pretty graph for after people already trust the data.

The call we'd make#

Backstage lives or dies on trust in the data, and trust comes from automation, not diligence. Auto-discover everything, enforce ownership in CI, put your docs inside it, and add a scorecard leadership actually looks at. If you're relying on engineers to manually register and update services, cancel the project now and save yourself the graveyard. Ours went from 60 rotting entries to 380 accurate ones the day we stopped asking humans to do a robot's job.

Before you invest this much in the catalog, it's worth checking whether Backstage is even the right call for your team size in the first place — see internal developer platforms: is Backstage worth it?

Explore topics:Infrastructure
React

Get the DevOps Troubleshooting Cheat Sheet

Subscribe and get our free one-page reference for the errors that eat an afternoon — CrashLoopBackOff, OOMKilled, Terraform state locks, and more — plus new guides as we publish them.

Share this post
KU

Kiril Urbonas

AI Engineer

560 articles
View all articles by Kiril Urbonas

You might have missed

Evergreen posts worth revisiting.