Scaffolder templates
Published on May 16th, 2022Overview
What Scaffolder Templates Are
Scaffolder templates are repeatable, self-service automation for creating and provisioning software and infrastructure.
They help organizations standardize best practices, reduce toil, and improve developer experience. Templates are a key part of the Roadie platform and are used to create new services and components, as well as to modify existing services and infrastructure. They are YAML-defined blueprints that automate the creation of new software components, services, or infrastructure within an engineering organization, as well as engage with existing services and infrastructure to modify them.
A template describes:
- What to generate (files, directories, config)
- What parameters to collect from the user (name, owner, repo, runtime, etc.)
- What actions to perform (create repos, apply IaC, set up CI/CD, register components, etc.)
They are run on demand by the user, which guides input through a form, and then runs defined actions. Roadie will execute the software template in an ephemeral container that is destroyed after the execution completes.
How Templates Are Used
1. Standardize New Services and Components
Teams can ensure every new microservice, library, or UI package follows the organization’s:
- tech stack standards
- folder structure
- security baselines
- best practices
2. Automate Repetitive Setup
Templates can automate tasks such as:
- creating a repository in your SCM (e.g. GitHub, GitLab, Bitbucket, Azure DevOps)
- pushing starter code to the repository
- applying Terraform modules
- provisioning cloud resources
- enabling CI/CD pipelines
- registering the component in the Roadie Catalog
3. Enable Self-Service Infrastructure
Engineers can request infrastructure or resources such as:
- databases
- service accounts
- enabling or disabling feature flags
- creating ephemeral environments
The template handles provisioning so engineers don’t need to file tickets or perform manual actions.
4. Enforce Governance and Golden Paths
Templates encode "how we build software here," ensuring:
- security requirements are met
- compliance metadata is captured
- observability and runtime configuration is always added
5. Scale Engineering Workflows
Templates transform long manual checklists into one-click or one-form operations, allowing teams to scale without extra overhead. This is especially useful for:
- onboarding new engineers
- performing repetitive tasks
- ensuring consistency across teams
Parts of a Template
Header Section
The header section is required for every template and contains information to configure the task and show details about the task on the "Create Component" page.
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: hello-world-template
title: Hello World
description: Says Hello to a specified name.
spec:
owner: default/engineering
type: service
apiVersion
This is a required field and should be set to scaffolder.backstage.io/v1beta3
kind
A Scaffolder template is also an Entity in Roadie. In order to configure this entity as a template you must set the kind to Template
metadata
The metadata field contains some data that appears on the template card that appears on the "Create Component" page.
spec
The spec field contains owner and type. Owner refers to the Roadie group or user that owns the Scaffolder task e.g. default/engineering. Type refers to the type of template. It can be set to anything and appears on the scaffolder template card in the "Create Component" page.
Form Input
The form input fields and steps are defined in the parameters section of the template. The parameters yaml is based on react-jsonschema-form and you can find the available syntax options there and examples here .
You can choose to break up the parameter prompting into form steps or collect all the parameters in one single step. Each parameter can be one of a few types: string, number, array or object. Here is an example of a single parameter form field:
parameters:
- title: Your Name
required:
- name
properties:
name:
type: string
parameters
The parameters is an array of objects that define the form input fields and steps.
Each object contains the following fields:
title: The title of the form steprequired: An array of required fieldsproperties: An object with the properties of the form field
properties
The properties object contains the form fields to be displayed in the form.
Some common fields are:
name: This is the field object key that will be used to reference the field in the template.type: The type of the form fieldtitle: The title of the form fielddescription: The description of the form fieldrequired: Whether the field is requireddefault: The default value of the field
Actions Performed
The steps section defines the actions that are taken by the scaffolder template when it is run as a task. The scaffolder initially creates a temporary directory referred to as the workspace, in which files are downloaded, generated, updated and pushed to some external system. Each step that is defined is run in order.
You can refer to the value of a parameter using the syntax ${{ parameters["name"] }} e.g.
steps:
- id: log-message
name: Log Message
action: debug:log
input:
message: 'Hello, ${{ parameters["name"] }}'
If the parameter id does not contain a special character you can also refer to it using the dot syntax ${{ parameters.name }}
You can find all the available actions to your Roadie instance by visiting the following page from within your Roadie tenant:
https://<tenant-name>.roadie.so/create/actions
Outputs from previous steps
You can refer to the output of a previous step using the following syntax:
${{ steps["publish-step-id"].output.repoContentsUrl }}
If the step id does not contain a special character you can also refer to it using the dot syntax.
${{ steps.publish.output.repoContentsUrl }}
Looping
You can use array type form inputs or step outputs to repeat action steps multiple times. e.g.
- id: log-description
name: Log Message
each: ['Brian', 'Ian']
action: debug:log
input:
message: 'Hello, ${{ each.value }}!'
Accessing the logged in user
You can refer to the user entity reference for the logged in user using the following syntax:
${{ user.ref }}
If this entity reference exists in the Roadie Catalog, you can also make use of the details contained within the users entity by using the following:
${{ user.entity.metadata.name }}
or access the details contained within the user's profile.
${{ user.entity.spec.profile.email }}
Conditional Steps
You can conditionally execute a scaffolder action based on an input parameter.
steps:
- action: debug:log
id: debug-log
if: ${{ parameters.name }}
name: Log Hello World
input:
message: 'Hello, ${{ parameters.name }}!'
Advanced
Calling an internal API
If you need a scaffolder step to contact a custom authenticated service or any public API for that matter that is not currently supported by a built-in action, you can do that using a combination of the http:backstage:request action and a Roadie proxy configuration.
Start by creating a proxy configuration as described in this page
Then you can add a step to call that API using the http:backstage:request action as follows:
steps:
- action: http:backstage:request
id: http-request
name: Create a thing on the acme service
input:
method: POST
path: "/api/proxy/acme/thing"
- action: debug:log
id: log-result
name: Log the result of creating the thing
input:
message: "The response code was ${{ steps["http-request"].output.code }}'
Escaping syntax
If you need to pass variable substitution syntax through without it being interpreted, you can escape the syntax by wrapping it like so ${{ '${{ parameters.something }}' }}.
Creating re-usable snippets
You can inject in re-usable snippets of yaml into a template using the $yaml operator like so:
templates/debug-step.yaml
- name: Debug log 2
id: debug_log_2
action: 'debug:log'
input:
message: Second log
logging-template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: placeholder-example
title: Demonstrating the placeholder usage
description: Shows how to inject in a single re-usable step
spec:
owner: default/engineering
type: service
steps:
- name: Debug log 1
id: debug_log_1
action: 'debug:log'
input:
message: First log
$yaml: https://github.com/yourOrg/some-repo/blob/templates/debug-step.yaml
This can only be done for a single step as the re-usable section must be valid yaml.
Using a user's Github Token to execute template steps
You can use the user that runs the scaffolder template to open a PR or other Github based actions rather than opening it on behalf of the Roadie Github App by specifying the token field. The token must first be injected via the parameters by the RepoUrlPicker parameter as documented here
parameters:
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
# Here's the option you can pass to the RepoUrlPicker
requestUserCredentials:
secretsKey: USER_OAUTH_TOKEN
additionalScopes:
github:
# - admin:org # Needed if you want to create a repo
- workflow
allowedHosts:
- github.com
steps:
- action: publish:github:pull-request
id: create-pull-request
name: Create a pull request
input:
repoUrl: 'github.com?repo=reponame&owner=AcmeInc'
branchName: ticketNumber-123
title: 'Make some changes to the files'
description: 'This pull request makes changes to the files in the reponame repository in the AcmeInc organization'
# here's where the secret can be used
token: ${{ secrets.USER_OAUTH_TOKEN }}
Alternatively, if you don't need to build a repo URL you can use the OauthSecret field to intiate login only. The token is stored in a secret value in the same way as above.
parameters:
- title: User Login
required:
- isLoggedIn
properties:
isLoggedIn:
title: Is logged in
type: boolean
ui:field: OauthSecret
ui:options:
secretsKey: USER_OAUTH_TOKEN
host: gitlab.com