Backstage Software Templates: How I Scaffold Production-Ready Services
· Sourabh G Kulkarni
How Spotify Backstage software templates and the service catalog eliminate repetitive boilerplate, ensuring every microservice launches with verified CI/CD, observability, and clear ownership on day one.

When an engineering team builds a new service, they usually want to focus immediately on business logic and domain code. However, setting up a production-ready foundation from scratch requires significant upfront effort: configuring build tools, container files, continuous integration workflows, testing harnesses, observability hooks, and cloud infrastructure.
Without an automated baseline, teams often face common challenges:
- Manually assembling pipelines leads to subtle configuration inconsistencies across teams.
- Core requirements—like standardized health probes, metrics endpoints, and logging formats—have to be repeatedly re-implemented.
- Determining service ownership and maintenance responsibility becomes harder as organizations scale.
Spotify Backstage Software Templates (the Scaffolder) solve this by turning organization standards into a repeatable, self-service Golden Path. With an approved template, an engineer selects their framework, enters essential project metadata, and immediately gets a fully configured repository with verified CI/CD, container definitions, observability endpoints, and registered service ownership.
The Value: Standards Without Friction
In modern software delivery, platform teams aim to reduce cognitive load rather than enforce burdensome checklists. Standardizing the onboarding workflow provides immediate advantages:
- Day-One Observability: Every new service starts with pre-configured Prometheus metrics scraping, health checks (
/healthz), and structured logging out of the box. - Consistent Delivery: Build pipelines follow audited security practices, automated testing runs by default, and multi-stage container builds prevent oversized artifacts.
- Clear Ownership & Governance: Centralizing service metadata makes incident response straightforward—every component has an unambiguous owning team and clear runbooks attached.
As discussed in DevOps to platform engineering and golden paths without the buzzwords, platform engineering isn't about imposing restrictive mandates. It is about making the right operational path the easiest path.
Anatomy of a Backstage Software Template
Backstage Software Templates are declared in simple YAML manifests (template.yaml) stored directly in git. Each template is composed of three essential blocks: Parameters, Steps, and Output.
┌─────────────────────────────────────────────────────────────┐
│ Backstage Template Workflow │
├─────────────────┬─────────────────────────┬─────────────────┤
│ 1. Parameters │ 2. Steps │ 3. Output │
│ (Developer UI) │ (Scaffolder Actions) │ (Repo & Links) │
└────────┬────────┴────────────┬────────────┴─────────┬───────┘
│ │ │
▼ ▼ ▼
User inputs Fetch skeleton → Open PR / Repo
(name, owner, Render Cookiecutter Register Component
runtime) Publish to GitHub in Service Catalog
1. Parameters: Keep Forms Radical and Short
A fatal mistake platform teams make is turning a template into a 20-question questionnaire. If developers have to pick CIDR ranges, ingress classes, state buckets, and CPU quota sizes, they will abandon the portal and go back to cloning old repositories.
Keep the input form focused on application intent:
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: python-fastapi-service
title: Python FastAPI Microservice
description: Scaffold a production-ready Python service with Docker, CI/CD, and metrics
spec:
owner: platform-team
type: service
parameters:
- title: Service Details
required:
- component_id
- description
- owner
properties:
component_id:
title: Service Name
type: string
description: Unique kebab-case name of the service
ui:field: EntityNamePicker
description:
title: Description
type: string
owner:
title: Owning Team
type: string
ui:field: OwnerPicker
ui:options:
allowedKinds:
- Group
2. Steps: The Scaffolder Action Pipeline
The spec.steps block executes a chain of modular, battle-tested Scaffolder actions.
Here is what a robust production pipeline does:
steps:
- id: template
name: Fetch and Templatize Skeleton
action: fetch:template
input:
url: ./skeleton
values:
component_id: ${{ parameters.component_id }}
description: ${{ parameters.description }}
owner: ${{ parameters.owner }}
- id: publish
name: Publish Repository to GitHub
action: publish:github
input:
allowedHosts: ['github.com']
description: ${{ parameters.description }}
repoUrl: github.com?owner=acme-corp&repo=${{ parameters.component_id }}
defaultBranch: main
repoVisibility: private
- id: register
name: Register Component in Catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish'].output.repoUrl }}
catalogInfoPath: '/catalog-info.yaml'
output:
links:
- title: Open GitHub Repository
url: ${{ steps['publish'].output.remoteUrl }}
- title: View Service in Backstage Catalog
icon: catalog
entityRef: ${{ steps['register'].output.entityRef }}
The Anchor: catalog-info.yaml in Git
The single most critical file generated by the template is catalog-info.yaml, which lives at the root of the newly created repository:
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: order-processing-service
description: Handles customer checkout validation and billing settlement
tags:
- python
- payments
annotations:
github.com/project-slug: acme-corp/order-processing-service
prometheus.io/rule: order_service_latency
pagerduty.com/integration-key: pd-service-orders
spec:
type: service
lifecycle: production
owner: group:checkout-team
system: payment-infrastructure
Why Storing catalog-info.yaml in Git Matters
- Ownership as Code: Any change to service ownership or runbook URLs goes through a standard Git pull request.
- Self-Healing Catalog: If an engineer deletes a repository or archives a project, Backstage detects the missing file and drops the component from the active catalog.
- Day-One Incident Routing: When an alert fires in PagerDuty or Grafana, the link back to Backstage immediately reveals the owning team, current on-call engineer, API documentation, and Git commit history.
What Every Scaffolded Service Gets Out of the Box
A Golden Path template is only as good as the baseline standards baked into its skeleton. When our developers scaffold a service, they never write boilerplate infrastructure:
- Multi-Stage Dockerfile: An optimized container build using non-root runtime users and small base images (as explored in Why your Docker image is 1 GB).
- Standard CI/CD Approval Pipelines: A workflow that builds once, runs security scans, and promotes the exact same container digest across Dev, UAT, and Production approval gates.
- Telemetry & Health Checks: Pre-wired endpoints:
/healthzfor liveness and readiness probes in Kubernetes./metricsfor Prometheus scraping.
- Kubernetes Baseline Manifests: Pre-configured deployment YAML with sensible CPU/memory requests and limits, PodDisruptionBudgets, and ingress rules.
Common Pitfalls to Avoid
- Creating monolithic "do-everything" templates: Don't attempt to build a single mega-template with dozens of checkboxes. Instead, create small, focused, runtime-specific templates (Go Microservice, Python Worker, Next.js Web App).
- Hiding the pipeline logs: When a developer clicks "Create", stream the scaffolder execution logs live in the UI. If a step fails (e.g., GitHub organization permissions), the developer should immediately see why rather than staring at an infinite spinning wheel.
- Forgetting template maintenance: Templates themselves are software. Put your template skeletons in automated testing pipelines that periodically scaffold an instance, run tests, and verify that dependencies haven't broken.
The Verdict
Backstage Software Templates transform platform engineering from a ticket-based bottleneck into a frictionless self-service engine.
The goal isn't just to save twenty minutes of setup time when creating a repo. The real win is that six months down the line, every microservice in your organization shares the same logging structure, the same deployment cadence, the same security posture, and a clearly identifiable owner.