Certified Backstage Associate (CBA)

Templates

Demo Creating a Template

In this walkthrough, we'll build a reusable Backstage template for provisioning a Node.js API using Express.js. By standardizing your project setup, every new API automatically includes:

ToolPurposeExample Command
ESLintLintingnpm run lint
PrettierCode formattingnpm run format
JestAutomated testingnpm run test
GitHub ActionsCI/CD.github/workflows/ci.yml
Express.jsAPI frameworknpm install express

The image lists organizational requirements, including tools for linting (eslint), formatting (prettier), testing (jest), CI/CD pipeline (GitHub Actions), and API library (express.js).


High-Level Workflow

The platform team maintains a blueprint repository containing a template.yaml. When a developer fills out a form in Backstage:

  1. Backstage fetches the project skeleton.
  2. It injects parameters (name, owner, repo URL).
  3. A new GitHub repository is created and registered automatically.

The image illustrates a workflow involving a platform team and a developer, featuring a form for project creation, a GitHub repository, and a YAML template. It visually represents steps in a process, likely related to software development or deployment.


1. Project Skeleton

Your blueprint (“Backstage Express API blueprint”) provides starter code:

  • package.json with scripts for start, dev, test, format, lint
  • .nvmrc (Node.js version: v20.11.0)
  • .gitignore (ignoring node_modules/)
  • src/ directory with a minimal Express endpoint
  • .github/workflows/ci.yml for GitHub Actions

In the IDE, it looks like this:

The image shows a Visual Studio Code interface with a file explorer open on the left, displaying various project files, and a `.gitignore` file open in the editor. The terminal at the bottom shows a Windows command prompt.

package.json

{
  "name": "project-name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node src/index.js",
    "dev": "nodemon src/index.js",
    "test": "jest",
    "test:ci": "jest --ci",
    "format": "prettier --write .",
    "format:check": "prettier --check .",
    "lint": "eslint .",
    "lint:fix": "eslint --fix ."
  },
  "type": "module",
  "keywords": [],
  "author": ""
}

Node Version

Make sure to update .nvmrc when your team upgrades Node.js:

v20.11.0

Express API (src/index.js)

import express from 'express';

const app = express();

app.get('/', (req, res) => {
  res.send('Hello from your Express API!');
});

const port = process.env.PORT ?? 4000;
app.listen(port, () => {
  console.log(`API listening on port ${port}`);
});

GitHub Actions Workflow (.github/workflows/ci.yml)

name: CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  quality-checks:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version-file: .nvmrc
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Check formatting with Prettier
        run: npm run format:check

      - name: Run tests
        run: npm run test:ci

2. Developer Experience

Developers select the Node.js + Express template in Backstage’s Create UI, fill in project fields, and click Create. Everything else is automated.

The image shows a web interface for creating new software components using templates, specifically featuring options for Node.js API with Express.js and an example Node.js template. The interface includes a sidebar with navigation options and a search bar.

The image shows a web interface for creating a new software component using a Node.js API with Express.js template. It includes fields for entering project information such as the component name and owner.

The image shows a web interface for creating a new software component using a Node.js API with Express.js template. It includes fields for specifying the repository location on GitHub.

Backstage shows real-time progress:

The image shows a web interface for running an "api-express-template" task in Backstage, with steps for fetching, publishing, and registering. The sidebar includes options like Home, APIs, Docs, and Create.

Once complete, the GitHub repository is created:

The image shows a GitHub repository page for a project named "inventory-service," displaying a list of files and folders with their initial commit status. The repository is private and written in JavaScript.

Backstage also registers the component automatically:

The image shows a dashboard interface for an "inventory-service" component in Backstage, displaying details like owner, lifecycle, and relations. It includes sections for overview, CI/CD, API, dependencies, and documentation.


3. Exploring Built-in Actions

Backstage Scaffolder comes with many pre-built actions. For example:

ActionPurpose
github:actions:dispatchTrigger a GitHub Actions workflow
github:repo:pushPush generated code to a GitHub repository
fetch:templateFetch and render a template repository

The image shows a user interface for "Backstage" with a section titled "Installed actions," specifically highlighting the "github:actions:dispatch" action, which allows dispatching a GitHub Action workflow for a given branch or tag. It includes input fields for repository location, workflow ID, branch or tag name, workflow inputs, and authentication token.

The image shows a Backstage interface with details about a GitHub repository push action, including input parameters and their descriptions.

You can preview parameters for fetch:template in the form playground:

The image shows a screenshot of a Backstage interface with a section titled "fetch:template," detailing input parameters for a templating action. The left sidebar includes navigation options like Home, APIs, Docs, and a "Create..." button.


4. Registering the Template

Register your template.yaml so Backstage displays it in the Create UI. You have two options:

  1. UI Registration: Paste the URL of your template YAML.
  2. Import: Select Import and choose from your templates repository.

The image shows a user interface for registering an existing component in a Backstage app, with a URL input field and an "ANALYZE" button. The sidebar includes navigation options like Home, APIs, Docs, and Create.

The image shows a user interface for registering an existing component in a Scaffolded Backstage App, with options to select a URL, review entities, and an "IMPORT" button highlighted.


5. Using the Template

Once registered, your Node.js + Express template appears in Create. Select it, fill in details, and click Create:

The image shows a web interface for creating new software components using templates, specifically for Node.js with Express.js and a Node.js template. A cursor is hovering over the "CHOOSE" button for one of the templates.

The image shows a web interface for creating a new component using a Node.js API with Express.js template. It includes fields for project information such as the component name and owner.

After creation, view your new service dashboard:

The image shows a dashboard interface for a "video-processing" service in Backstage, displaying details like owner, lifecycle, and relations. The sidebar includes options for Home, APIs, Docs, and Create.


6. Template YAML Example

Here’s a complete template.yaml that ties everything together:

apiVersion: backstage.io/v1beta3
kind: Template
metadata:
  name: api-express-template
  title: Node.js API w/ Express.js
  description: A template for provisioning Express.js APIs with built-in CI/CD and code quality tools
spec:
  owner: user:guest
  type: service

  parameters:
    - title: Project Info
      required:
        - name
        - owner
      properties:
        name:
          title: Name
          type: string
          description: Unique component name
          ui:
            autofocus: true
        owner:
          title: Owner
          type: string
          description: Component owner
          ui:
            field: OwnerPicker
            options:
              catalogFilter:
                kind: [User, Group]

    - title: Choose Location
      required:
        - repoUrl
      properties:
        repoUrl:
          title: Repository Location
          type: string
          ui:
            field: RepoUrlPicker
            options:
              allowedHosts:
                - github.com

  steps:
    - id: fetch-base
      name: Fetch Base
      action: fetch:template
      input:
        url: https://github.com/Sanjeev-Thiyagarajan/backstage-express-api-blueprint
        values:
          name: ${{ parameters.name }}
          owner: ${{ parameters.owner }}

    - id: publish
      name: Publish to GitHub
      action: publish:github
      input:
        allowedHosts: ['github.com']
        description: Project ${{ parameters.name }}
        repoUrl: ${{ parameters.repoUrl }}

    - id: register
      name: Register Component
      action: catalog:register
      input:
        repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
        catalogInfoPath: /catalog-info.yaml

  output:
    links:
      - title: Repository
        url: ${{ steps.publish.output.remoteUrl }}
      - title: Open in Catalog
        icon: catalog
        entityRef: ${{ steps.register.output.entityRef }}

Templating Values

In your skeleton’s package.json and catalog-info.yaml, reference parameters using the values object:

{
  "name": "${{ values.name }}",
  "version": "1.0.0"
}
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: '${{ values.name | dump }}'
spec:
  type: service
  owner: '${{ values.owner }}'
  lifecycle: experimental

Watch Video

Watch video content

Previous
Demo Template Basics