In the last few blog posts, we dived into the core functionalities and features of Backstage. That included the Backstage Software Catalog, Backstage Search, or Techdocs. Another great part of Backstage is the Software Template functionality and we will cover that in this and the next blog posts.
What are Software Templates in Spotify Backstage
Backstage Software Templates allow users to create new software components effortlessly. These templates can handle various tasks, such as accepting parameters, processing them, generating skeleton code, creating a GitHub repository, and more.
Users can access these templates by clicking the „Create…“ button in the navigation bar. This leads to the „Create a New Component“ page, where all available templates are listed. Additionally, all templates are registered as entities of type „kind: Template“ in the Software Catalog and can be executed from their respective detail pages.
How can we register existing templates
As described, Backstage Software Template can be registered by using the graphical user interface. Another way is to reference them in app-config.yaml. Those templates can be either loaded from a file location, or better from a Git Url. Let’s take a look in the default app-config.yaml:
catalog:
import:
entityFilename: catalog-info.yaml
pullRequestBranchName: backstage-integration
rules:
- allow: [Domain, Systems, Group, Component, System, API, Resource, Location]
locations:
# Local example data, file locations are relative to the backend process, typically `packages/backend`
- type: file
target: ../../examples/entities.yaml
# Local example template
- type: file
target: ../../examples/template/template.yaml
rules:
- allow: [Template]
We can see a local example template and a rule, that from this location only Templates are allowed. Let’s have a look on the template itself:
apiVersion: t.backstage.io/v1beta3
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-template
kind: Template
metadata:
name: example-nodejs-template
title: Example Node.js Template
description: An example template for the scaffolder that creates a simple Node.js service
spec:
owner: user:guest
type: service
# These parameters are used to generate the input form in the frontend, and are
# used to gather input data for the execution of the template.
parameters:
- title: Fill in some steps
required:
- name
properties:
name:
title: Name
type: string
description: Unique name of the component
ui:autofocus: true
ui:options:
rows: 5
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
# These steps are executed in the scaffolder backend, using data that we gathered
# via the parameters above.
steps:
# Each step executes an action, in this case one templates files into the working directory.
- id: fetch-base
name: Fetch Base
action: fetch:template
input:
url: ./content
values:
name: ${{ parameters.name }}
# This step publishes the contents of the working directory to GitHub.
- id: publish
name: Publish
action: publish:github
input:
allowedHosts: ['github.com']
description: This is ${{ parameters.name }}
repoUrl: ${{ parameters.repoUrl }}
# The final step is to register our new component in the catalog.
- id: register
name: Register
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
catalogInfoPath: '/catalog-info.yaml'
# Outputs are displayed to the user after a successful execution of the template.
output:
links:
- title: Repository
url: ${{ steps['publish'].output.remoteUrl }}
- title: Open in catalog
icon: catalog
entityRef: ${{ steps['register'].output.entityRef }}
Let’s discuss this sample script in details:
Basically, the script will create a simple Node.js service.
The first section will provide some basic information:
The next part is the specification (spec), with the following information:
– owner: Specifies the owner of the template (`user:guest`).
– type: Defines the type of component this template creates (`service`).
Software Template Parameters
Now, lets talk about the parameters:
Parameters in a Backstage Software Template are used to gather necessary input data from the user through an interactive form in the frontend. These inputs are then utilized during the execution of the template. Let’s explain tat:
- Title: Each parameter group can have a title that describes what kind of inputs it will gather.
- Required Fields: A list of fields that are mandatory for the user to fill out.
- Properties: Defines the specifics of each input field, including:
- Title: The label shown to the user.
- Type: The data type of the input (e.g., string, number).
- Description: Additional information about the input.
- UI Options: Customizes the appearance and behavior of the input field (e.g., autofocus, rows for text fields).
After having discussed the input, let’s see what the template actually is doing. Software templates can be seen like workflows, that are executed sequentially.
Software Template Steps
Steps define the sequential actions executed in the scaffolder backend to automate the creation of software components. Here’s a concise overview:
- ID: A unique identifier for each step.
- Name: A human-readable name describing what the step does.
- Action: The specific action to be performed in the step. Actions can include tasks like fetching templates, publishing to repositories, or registering components.
- Input: Data required to perform the action. This can include parameters collected from the user or outputs from previous steps.
Example Breakdown
Step 1: Fetch Base Template
- ID: fetch-base
- Name: Fetch Base
- Action: fetch:template
- Input:
- URL: Path to the template content (e.g., ./content).
- Values: Variables to replace in the template (e.g., name parameter).
Step 2: Publish to GitHub
- ID: publish
- Name: Publish
- Action: publish:github
- Input:
- Allowed Hosts: List of allowed repository hosts (e.g., github.com).
- Description: Repository description using parameters.
- RepoUrl: Repository URL provided by the user.
Step 3: Register Component
- ID: register
- Name: Register
- Action: catalog:register
- Input:
- RepoContentsUrl: URL of the repository contents from the publish step.
- CatalogInfoPath: Path to the catalog information file (e.g., /catalog-info.yaml).
Why do we need steps?
Steps in Backstage software templates are essential because they:
- Define a clear sequence of automated tasks.
- Allow the use of dynamic inputs and outputs to customize each action.
- Ensure the template execution is systematic and reproducible.
In essence, steps guide the scaffolding process, making it possible to automate complex workflows and ensure consistency across different component creation tasks.
With that being said, let’s show the content which is used at the fetch-base step:
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: ${{ values.name | dump }}
spec:
type: service
owner: user:guest
lifecycle: experimental
In essence, the Scaffolder template replaces the expression ${{ values.name }} and hence creates a Component.
That’s enough for today. In the next blog post, we will show some advanced Scaffolder/ Software template stuff.
> Click here for Part 15: Backstage Software Templates II