> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Creating a Template

> Guide to building a Backstage Scaffolder template that provisions Node.js Express starter repositories with ESLint, Prettier, Jest, GitHub Actions, and automatic catalog registration

In this guide you'll learn how to create a Backstage Scaffolder template that provisions a starter Node.js API repository (Express) with your organization conventions baked in. The template will:

* scaffold a repository with ESLint, Prettier, Jest, GitHub Actions CI, and a sample Express app
* create the GitHub repository
* register the new component in the Backstage catalog

This enables developers to create new services quickly with the correct tooling and guardrails in place.

## Organization requirements (example)

Use these as a checklist when building the skeleton (blueprint) repository.

| Requirement   | Example                              |
| ------------- | ------------------------------------ |
| Linter        | ESLint                               |
| Formatter     | Prettier                             |
| Testing       | Jest                                 |
| CI/CD         | GitHub Actions (`.github/workflows`) |
| API framework | Express.js                           |

## High-level flow

1. Platform team creates a skeleton (blueprint) repository that contains:
   * `package.json`, ESLint & Prettier config, tests, GitHub workflows
   * a sample Express app (`src/`), and a `catalog-info.yaml`
2. Upload the skeleton to GitHub (e.g., `backstage-express-api-blueprint`).
3. Create a Scaffolder `Template` YAML that:
   * renders a multi-page form for the developer (project name, owner, repo location)
   * fetches the skeleton, templates values into files, publishes the repo, and registers the component
4. Developer uses the template through Backstage Create UI — Backstage runs the template and provisions the repo and catalog entry.

<Callout icon="lightbulb" color="#1CB2FE">
  Design templates so platform-spec decisions (lint, test, CI) are enforced by the skeleton. Use consistent parameter names (e.g., `name`, `owner`) to simplify templating and avoid parsing pitfalls.
</Callout>

This is what the template tile will look like inside Backstage:

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/DMHG6m-am03QxTqW/images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-create-component-nodejs-templates.jpg?fit=max&auto=format&n=DMHG6m-am03QxTqW&q=85&s=78d0a63427c3d0e1ea400036d94894b4" alt="A web app screenshot of the Backstage &#x22;Create a new component&#x22; page showing template cards for Node.js services (e.g., &#x22;Node.JS API w/ express.js&#x22; and &#x22;Example Node.js Template&#x22;). The left sidebar shows navigation items like Home, APIs, Docs and Create." width="1920" height="1080" data-path="images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-create-component-nodejs-templates.jpg" />
</Frame>

Developer fills in the template form (example):

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/DMHG6m-am03QxTqW/images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-create-nodejs-express-inventory-service.jpg?fit=max&auto=format&n=DMHG6m-am03QxTqW&q=85&s=9e40a9818552697b22265578d64ca4a5" alt="A screenshot of the Backstage &#x22;Create a new component&#x22; page showing the Node.JS API w/ express.js template. The form displays a component name &#x22;inventory-service&#x22; and an owner field set to &#x22;group:default/dev.&#x22;" width="1920" height="1080" data-path="images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-create-nodejs-express-inventory-service.jpg" />
</Frame>

Backstage runs the template and shows run progress (fetch, publish, register):

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/DMHG6m-am03QxTqW/images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-create-run-progress-fetch-publish.jpg?fit=max&auto=format&n=DMHG6m-am03QxTqW&q=85&s=b471ac282551107d51e69e4926465ee7" alt="A screenshot of the Backstage web UI showing a run titled &#x22;Run of api-express-template&#x22; with a three-step progress bar where &#x22;Fetch Base&#x22; is complete, &#x22;Publish&#x22; is in progress, and &#x22;Register&#x22; is pending. The left sidebar shows navigation items like Home, APIs, Docs and a highlighted &#x22;Create...&#x22; option." width="1920" height="1080" data-path="images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-create-run-progress-fetch-publish.jpg" />
</Frame>

After completion, the new repository appears in GitHub with the skeleton files (package.json, `.github/workflows`, `src/`, tests, etc.):

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/DMHG6m-am03QxTqW/images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/inventory-service-repo-file-list.jpg?fit=max&auto=format&n=DMHG6m-am03QxTqW&q=85&s=382a48f933d672f213c34c560c0c9b27" alt="A screenshot of a GitHub repository page for &#x22;inventory-service,&#x22; showing the file list (folders like .github/workflows, src, tests and files such as .gitignore, package.json) and the repo sidebar with activity and language info." width="1920" height="1080" data-path="images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/inventory-service-repo-file-list.jpg" />
</Frame>

The scaffolder injects the provided values (for example, `inventory-service` in `package.json` and `catalog-info.yaml`):

```yaml theme={null}
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: "inventory-service"
spec:
  type: service
  owner: group:default/dev
  lifecycle: experimental
  dependsOn:
    - "resource:inventory-service-ec2"
```

Backstage catalog shows the registered component:

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/DMHG6m-am03QxTqW/images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-inventory-service-overview-missing-relations.jpg?fit=max&auto=format&n=DMHG6m-am03QxTqW&q=85&s=01d10aab14f6d7b195cdaa6c1b75cd8b" alt="A screenshot of the Backstage catalog showing the &#x22;inventory-service&#x22; component overview page with an alert about missing related entities and panels for About (owner: dev, lifecycle: experimental) and Relations (graph linking dev to inventory-service)." width="1920" height="1080" data-path="images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-inventory-service-overview-missing-relations.jpg" />
</Frame>

## Template Form Playground

Backstage includes a Template Form Playground to design and test scaffolder form UI interactively. Use it to verify pages, required fields, and UI widgets like `OwnerPicker` and `RepoUrlPicker`.

A minimal playground example (two parameter pages and one fetch step):

```yaml theme={null}
# Playground example showing two parameter pages and a single fetch step
parameters:
  - title: Fill in some steps
    required:
      - name
    properties:
      name:
        title: Name
        type: string
        description: Unique name of the component
      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:
          allowedHosts:
            - github.com

steps:
  - id: fetch-base
    name: Fetch Base
    action: fetch:template
```

<Callout icon="warning" color="#FF6B6B">
  The Template Form Playground validates as you type and can show transient validation errors. If you see unexpected errors, edit the YAML in an external editor and paste it back into the playground.
</Callout>

## Create the actual template file (api-template.yaml)

Below is a consolidated, working example of a scaffolder Template for a Node.js Express API. Important notes:

* Use parameter names without hyphens (e.g., prefer `name` over `project-name`).
* The `fetch:template` step downloads a skeleton and applies `values` to files in the skeleton.
* `publish:github` needs repository creation permissions on the GitHub token configured in Backstage.
* `catalog:register` needs the `catalog-info.yaml` path inside the new repo.

```yaml theme={null}
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: api-express-template
  title: Node.JS API w/ express.js
  description: A template for provisioning APIs with Express.JS
spec:
  owner: user:guest
  type: service

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

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

  # Steps executed by the scaffolder backend
  steps:
    - id: fetch-base
      name: Fetch Base
      action: fetch:template
      input:
        # URL of the skeleton repository or a relative path (if the template bundle contains the skeleton)
        url: https://github.com/Sanjeev-Thiyagarajan/backstage-express-api-blueprint
        values:
          name: ${{ parameters.name }}
          owner: ${{ parameters.owner }}

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

    - id: register
      name: Register
      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 }}
```

### Notes about the template and skeleton

* `fetch:template` downloads a skeleton and applies templating replacements using `values`.
* Provide `values` for each placeholder used inside the skeleton (e.g., package.json, catalog-info.yaml).
* Avoid hyphens in parameter names to prevent parsing ambiguities.
* Ensure the GitHub token used by Backstage has repository creation and workflow write permissions if your skeleton includes GitHub Actions.

Fetch template docs (reference image):

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/DMHG6m-am03QxTqW/images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-fetch-template-docs-ui.jpg?fit=max&auto=format&n=DMHG6m-am03QxTqW&q=85&s=6724022bc11b43b2397033a13c788ff8" alt="A screenshot of the Backstage web UI showing documentation for fetch actions (including &#x22;fetch:template&#x22;), with input parameter tables, descriptions and examples. A dark left sidebar displays navigation items like Search, Home, APIs, Docs and a highlighted Create button." width="1920" height="1080" data-path="images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-fetch-template-docs-ui.jpg" />
</Frame>

## Make the skeleton template-ready

Replace hard-coded values in the skeleton repo with templating placeholders so the scaffolder can inject values at runtime.

package.json (template-ready):

```json theme={null}
{
  "name": "${{ values.name }}",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node src/index.js",
    "test": "jest",
    "test:ci": "jest --ci",
    "dev": "nodemon src/index.js",
    "format": "prettier --write",
    "format:check": "prettier --check",
    "lint": "eslint .",
    "lint:fix": "eslint --fix ."
  },
  "type": "module",
  "dependencies": {
    "express": "^4.21.2"
  },
  "devDependencies": {
    "jest": "^29.7.0",
    "nodemon": "^2.0.20",
    "prettier": "^2.8.8",
    "eslint": "^9.17.0"
  }
}
```

catalog-info.yaml (template-ready):

```yaml theme={null}
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: ${{ values.name | dump }}
spec:
  type: service
  owner: ${{ values.owner }}
  lifecycle: experimental
```

## Uploading the template to Backstage

You can make templates available to Backstage in several ways:

* Add the template YAML to a location listed in `app-config.yaml` (file or URL).
* Register it through the Backstage UI: Create → Manage Templates → Register an existing component.
* Use an entity provider to discover templates dynamically from a repository.

If you register via the UI and see "template not of allowed kind for that location", ensure your catalog integration `rules` include `Template`.

Store templates in a dedicated repo (recommended) — for example `backstage-templates` with a `templates/` directory:

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/DMHG6m-am03QxTqW/images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/github-backstage-templates-api-template-click.jpg?fit=max&auto=format&n=DMHG6m-am03QxTqW&q=85&s=43571a2698afd59a07ad9fec69255dbe" alt="A screenshot of a GitHub repository page showing the backstage-templates/templates directory with files like api-template.yaml, template10.yaml, and template11.yaml. A green pointer/cursor is clicking the api-template.yaml entry in the file list." width="1920" height="1080" data-path="images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/github-backstage-templates-api-template-click.jpg" />
</Frame>

Registering a template via the UI:

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/DMHG6m-am03QxTqW/images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-register-component-import-wizard.jpg?fit=max&auto=format&n=DMHG6m-am03QxTqW&q=85&s=36eff74460ba5faaa2ba243cb0e09b3c" alt="Screenshot of the Backstage web UI showing the &#x22;Register an existing component&#x22; wizard with steps to select a URL, select locations, review discovered entities, and an emphasized &#x22;IMPORT&#x22; button. A left navigation bar lists Home, APIs, Docs and Create, while the right panel explains linking to an entity file or repository." width="1920" height="1080" data-path="images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-register-component-import-wizard.jpg" />
</Frame>

## GitHub authentication & permissions

* The GitHub integration token used by Backstage must have permissions to create repositories if you use `publish:github`.
* If your skeleton includes GitHub Actions workflows, ensure the token has the required workflow permissions to push workflows.
* Configure the token in Backstage integrations (e.g., `app-config.yaml`) so `publish:github` works.

## Create a component with the template

Once the template is registered, use the Create flow to provision a component. Example run progress:

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/DMHG6m-am03QxTqW/images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-run-api-express-template-progress.jpg?fit=max&auto=format&n=DMHG6m-am03QxTqW&q=85&s=3e9d76dbad40c4c594e9edaceee9f985" alt="A screenshot of the Backstage web UI showing a run page for &#x22;api-express-template&#x22; with a horizontal progress timeline of completed steps (Fetch Base, Publish, Register). The left sidebar displays navigation items like Home, APIs, Docs, and Create." width="1920" height="1080" data-path="images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-run-api-express-template-progress.jpg" />
</Frame>

The created component page shows ownership and relations:

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/DMHG6m-am03QxTqW/images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-video-processing-about-dev-relations.jpg?fit=max&auto=format&n=DMHG6m-am03QxTqW&q=85&s=e1a72423a0216f2c928d75c68a1bea2a" alt="A Backstage web UI page for a &#x22;video-processing&#x22; service component, showing the About panel (with owner &#x22;dev&#x22; and lifecycle &#x22;experimental&#x22;) and options like View Source and View TechDocs. The right side displays a relations graph linking the &#x22;dev&#x22; owner to the video-processing component." width="1920" height="1080" data-path="images/Prep-Course-Certified-Backstage-Associate-CBA-Certification/Templates/Demo-Creating-a-Template/backstage-video-processing-about-dev-relations.jpg" />
</Frame>

Resulting package.json example (after templating):

```json theme={null}
{
  "name": "video-processing",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node src/index.js",
    "test": "jest",
    "test:ci": "jest --ci",
    "dev": "nodemon src/index.js",
    "format": "prettier --write",
    "format:check": "prettier --check",
    "lint": "eslint .",
    "lint:fix": "eslint --fix ."
  },
  "type": "module",
  "dependencies": {
    "express": "^4.21.2"
  },
  "devDependencies": {
    "@eslint/js": "^9.17.0",
    "eslint": "^9.17.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-jest": "^28.10.0",
    "globals": "^15.14.0",
    "jest": "^29.7.0",
    "nodemon": "^2.0.20",
    "prettier": "^2.8.8"
  }
}
```

Resulting `catalog-info.yaml` example:

```yaml theme={null}
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: "video-processing"
spec:
  type: service
  owner: group:default/dev
  lifecycle: experimental
```

## Recap / tips

* Design the user interface with `parameters`; reuse Backstage UI widgets using `ui:field` (e.g., `OwnerPicker`, `RepoUrlPicker`).
* Use `fetch:template` to download and template a skeleton; map `parameters` to `values`.
* Use `publish:github` to create and push the repository (requires appropriately permissioned GitHub token).
* Use `catalog:register` to add the new component to Backstage.
* Avoid hyphens in parameter names; prefer `name`, `owner`.
* If the Template Form Playground behaves oddly, edit YAML in an external editor and paste it back.

This pattern enables platform teams to bake best practices and guardrails into starter repositories so developers can quickly create production-ready services.

## Links and references

* Backstage Scaffolder docs: [https://backstage.io/docs/features/software-templates/using-templates](https://backstage.io/docs/features/software-templates/using-templates)
* Backstage Scaffolder actions (fetch, publish, register): [https://backstage.io/docs/features/software-templates/actions](https://backstage.io/docs/features/software-templates/actions)
* Backstage Catalog entities: [https://backstage.io/docs/features/software-catalog/overview](https://backstage.io/docs/features/software-catalog/overview)

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/certified-backstage-associate-cba/module/1c7142e3-0cb6-40ae-b5b6-77252f8c85b2/lesson/bdcf9a0b-92e8-4ce6-80c9-187b0e117a98" />
</CardGroup>
