Create a Service Template
Nowadays, creating new repositories for services or applications often involves a lot of repetitive tasks, such as setting up the project structure, adding CI pipelines, configuring deployment manifests and much more. As this can be a very good driver for standardization and productivity and can reduce cognitive load for developers, Backstage provides Software Templates to automate these tasks.
Software templates in Backstage are a combination of a form definition (to collect user input), a set of actions (to perform tasks) and a template (to generate files). In this section, we will create a simple Software Template to bootstrap new repositories for our services. In our example, we will create a simple template to create a new NodeJS service repository, with a Dockerfile and a GitHub Actions CI pipeline.
For simplicity, we will use the existing repository lab-backstage-basics we forked earlier as the template repository. Therefore, open the lab-backstage-basics repository in your favorite editor and create a new directory called templates in the root of the repository. In this directory, create a new file called nodejs-template.yaml with the following content:
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
# some metadata about the template itself
metadata:
name: nodejs-template
title: NodeJS Service
description: Template to create a NodeJS based Backstage service
spec:
owner: backstage/your-github-team
type: service
Please replace your-github-team with your actual GitHub team name. This is the metadata of our template, where we define the name, title, description, owner and type of the template.
In the next step, we will define some parameters for our template to collect user input when creating a new repository. Add the following section to the nodejs-template.yaml file:
parameters:
- title: Fill in some steps
required:
- name
- description
properties:
name:
title: Name
type: string
description: Unique name of the Service
description:
title: Description
type: string
description: Description of this Service
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
requestUserCredentials:
secretsKey: USER_OAUTH_TOKEN
additionalScopes:
github:
- workflow
allowedHosts:
- github.com
allowedOwners:
- your-github-organization
This section defines two parameter groups: The first group collects some basic information about the service, such as name, description and owner. The second group collects the repository location, where the new repository should be created. Please replace your-github-organization with your actual GitHub organization name. You might notice that there are some custom UI fields used in this section, such as OwnerPicker and RepoUrlPicker. These fields provide a better user experience when filling out the form in Backstage. Additionally, the RepoUrlPicker field is configured to request user credentials for creating the repository in GitHub.
You can find test forms and find information about the available UI fields in your Backstage installation at http://localhost:3000/create/edit.
In the next step, we will define some actions for our template to perform tasks when creating a new repository. Add the following section to the nodejs-template.yaml file:
steps:
- id: fetchBase
name: Fetch Base
action: fetch:template
input:
url: ../template-base
values:
name: ${{ parameters.name}}
description: ${{ parameters.description }}
- id: publish-repo
name: Publish Repository
action: publish:github
input:
gitAuthorName: ${{ user.entity.metadata.name }}
gitAuthorEmail: ${{ user.entity.spec.profile.email }}
repoUrl: ${{ parameters.repoUrl }}
description: ${{ parameters.description }}
token: ${{ secrets.USER_OAUTH_TOKEN }}
This section defines two steps: The first step fetches a base template from a local directory and replaces some values with the user input. The second step publishes the new repository to GitHub using the provided repository URL and user credentials.
📖Example Template Manifest
Putting it all together, your nodejs-template.yaml file should look like this:
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
# some metadata about the template itself
metadata:
name: nodejs-template
title: NodeJS Service
description: Template to create a NodeJS based Backstage service
spec:
owner: backstage/your-github-team
type: service
parameters:
- title: Fill in some steps
required:
- name
- description
properties:
name:
title: Name
type: string
description: Unique name of the Service
description:
title: Description
type: string
description: Description of this Service
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
requestUserCredentials:
secretsKey: USER_OAUTH_TOKEN
additionalScopes:
github:
- workflow
allowedHosts:
- github.com
allowedOwners:
- your-github-organization
steps:
- id: fetchBase
name: Fetch Base
action: fetch:template
input:
url: ../template-base
values:
name: ${{ parameters.name}}
description: ${{ parameters.description }}
- id: publish-repo
name: Publish Repository
action: publish:github
input:
gitAuthorName: ${{ user.entity.metadata.name }}
gitAuthorEmail: ${{ user.entity.spec.profile.email }}
repoUrl: ${{ parameters.repoUrl }}
description: ${{ parameters.description }}
token: ${{ secrets.USER_OAUTH_TOKEN }}
:::
Now, we'll have to modify the files in the `template-base` directory to use the values provided by the user. Therefore, we'll change hardcoded values in the files to use template variables instead. The files you need to modify are:
* `Dockerfile`
* `.github/workflows/build.yaml`
* `src/main.js`
* `catalog-info.yaml`
* `README.md`
For example, in the `README.md` file, you would change the content to:
```markdown
# ${{ values.name }}
This is the ${{ values.name }} service.
This way, when the template is used to create a new repository, the values provided by the user will be injected into the files. Backstage uses the Nunjucks templating engine for this purpose, so you can use Nunjucks syntax in your files.
:::validate Check your template variables To verify that your template variables are correctly set up, check the following:
- Open each file and ensure
${{ values.name }}and${{ values.description }}are used instead of hardcoded values - Make sure the syntax is exactly
${{ values.propertyName }}with the dollar sign and double curly braces - Verify that the property names match the parameter names defined in your template :::
After making these changes, commit and push the changes to the main branch of your lab-backstage-basics repository.
Finally, we need to register the template in the Backstage Catalog, so it can be used in the Backstage application. Therefore, open the app-config.yaml file in your backstage project and add the following catalog location:
catalog:
locations:
- type: url
target: https://github.com/your-github-organization/lab-backstage-basics/blob/main/template/nodejs-template.yaml
rules:
- allow: [Template]
This configuration tells Backstage to fetch the template from the specified URL and add it to the Catalog. Please replace your-github-organization with your current GitHub organization name.
After making this change, restart your Backstage application again, then navigate to the "Create" page in the Backstage application. You should see the "NodeJS Service" template listed there. You can now use this template to create new repositories for your NodeJS services.
When you fill out the form and submit it, Backstage will create a new repository in your GitHub organization using the provided information and the template we created. After some time, you should see the new repository appearing in the Backstage Catalog.
:::congratulations You have successfully created and used a Software Template in Backstage! :::
