Versioning and Deprecating Golden Paths

A golden path is a living product, not a one-time gift: the framework it scaffolds moves on, security requirements change, and last year’s template quietly becomes a liability. Without a versioning and deprecation discipline, you end up with a graveyard of half-current templates and services born onto paths you no longer support. This how-to versions golden-path templates, deprecates old ones cleanly, and guides teams to the current version. It extends Golden Paths & Paved Roads within Developer Experience & Self-Service Platforms.

Prerequisites

  • Backstage 1.20+ with golden paths implemented as scaffolder templates.
  • A version convention for templates — semantic versions or dated releases.
  • A signal for template lifecycle state, so the portal can show current, deprecated, or retired.
  • Adoption tracking, so you know who is on an old path before you deprecate it — see Tracking Golden Path Adoption.
Prerequisites for path versioning Templated paths, a version convention, a lifecycle signal, and adoption data enable clean versioning. templated paths version convention lifecycle signal adoption data Clean lifecycle no graveyard
Never deprecate blind — adoption data tells you who is on the old path so deprecation becomes a migration, not a surprise.

Exact Configuration

  1. Version the template and mark its lifecycle in metadata.

    # template.yaml
    apiVersion: scaffolder.backstage.io/v1beta3
    kind: Template
    metadata:
      name: nodejs-service-v2
      title: Node.js Service (v2)
      tags: [recommended]
      annotations:
        backstage.io/template-version: '2.1.0'
    spec:
      lifecycle: production
    
  2. Deprecate the old version so it is discouraged but still visible to those already on it.

    # template.yaml (old)
    metadata:
      name: nodejs-service-v1
      title: 'Node.js Service (v1 — deprecated)'
      tags: [deprecated]
    spec:
      lifecycle: deprecated
    
  3. Point teams to the current version with a migration note in the deprecated template’s output.

    # old template.yaml
    output:
      text:
        - title: This path is deprecated
          content: |
            Use **Node.js Service (v2)** for new services.
            Migration guide: /docs/golden-paths/nodejs-v1-to-v2
    
Template lifecycle states A path moves from recommended to deprecated to retired, with the current version always signposted. Recommended v2 · use this Deprecated v1 · migrate off Retired removed
Deprecated is a holding state, not a deletion — the old path stays visible with a migration note until adoption of it reaches zero.

Validation

# Requires curl, jq
# 1. Exactly one version per path is recommended
curl -s "${PORTAL_URL}/api/catalog/entities?filter=kind=template" \
  | jq '[.[] | select(.metadata.tags | index("recommended")) | .metadata.name]'
# Expected: one current template per path family

# 2. Deprecated templates are labeled, not deleted
curl -s "${PORTAL_URL}/api/catalog/entities?filter=kind=template" \
  | jq '[.[] | select(.spec.lifecycle=="deprecated") | .metadata.name]'
# Expected: old versions present with deprecated lifecycle

# 3. No new services are created from a deprecated path
psql -c "SELECT template, COUNT(*) FROM scaffolder_events
         WHERE at > now() - interval '30 days' AND template LIKE '%-v1' GROUP BY template;"
# Expected: zero, or a shrinking count
Path versioning validation checks One recommended version, deprecated paths still labeled, and no new services on the old path. One recommended per path Old labeled deprecated, kept No new on old count → 0
A shrinking count of new services on the old path is the green light to retire it — retiring before that number hits zero strands teams.

Edge Cases & Troubleshooting

Symptom Root Cause Resolution
Two versions both look current No single recommended tag Tag exactly one version recommended
Teams keep using the old path Deprecation not visible Retitle, tag deprecated, add a migration note
Retired path breaks existing services Removed the running scaffold’s support Retire the template, keep supporting scaffolded services
No migration guidance Deprecation without a path forward Ship a migration guide before deprecating
Version sprawl Every change makes a new template Reserve new versions for breaking changes
Path versioning pitfalls by class Ambiguous current versions and sprawl are versioning issues; invisible deprecation and missing guides are migration issues. Versioning ambiguous current version sprawl → one recommended Migration invisible deprecation no guide → label + ship guide first
Retiring the template must not break services already scaffolded from it — deprecation removes the on-ramp, not the road underneath existing traffic.

Frequently Asked Questions

When does a change warrant a new version instead of an edit?

Reserve a new version for a breaking change — a different framework major, an incompatible structure, a new required input. Non-breaking improvements should just update the current template in place, so teams get the fix without a migration. Minting a new version for every tweak is how you end up with the sprawl that makes the whole catalog feel untrustworthy.

How long should a deprecated path stay available?

Until adoption of it reaches zero and existing services have migrated or been accounted for. Deprecation is a signal, not a deadline you enforce blindly; pull the template only when the data shows nobody is starting new work on it. Rushing removal to hit a date strands the teams who had not migrated yet and erodes trust in the next deprecation you announce.