Skip to main content
In this lesson you’ll build a Backstage scaffolder template that creates a Node.js + Express API repository and provisions the underlying infrastructure (an EC2 instance) with Terraform. The template will:
  • Clone an infrastructure blueprint (Terraform code), templatize it, and publish it as a new repo.
  • Register the resulting Resource entity in the Backstage catalog.
  • Clone an application blueprint (Node.js + Express skeleton), templatize it, publish it as a new repo, and register the Component in the catalog.
  • Wire the created Component to depend on the newly created Resource so relations appear in Backstage.
A simple architecture diagram titled "Template Demo" showing an Organization icon on the left connected to a Template box containing an API icon and the Node.js logo. An arrow leads from the template to an AWS box with a chip/processor symbol, and a "Developers" label appears below.

Flow overview

  1. Platform/infrastructure teams maintain blueprint repositories:
    • infrastructure-IAC — core infra managed by the infra team (VPCs, shared resources).
    • ec2-infra-blueprint — per-app Terraform module/skeleton used by the template.
    • backstage-express-api-blueprint — Node.js + Express app skeleton.
  2. A developer opens the Backstage template UI, supplies project metadata (name, owner, destination repo), and selects an EC2 instance size.
  3. Backstage templatizes the infra blueprint, publishes it as <repo>-infra, and registers a Resource entity (type: compute).
  4. Backstage templatizes the app blueprint, publishes it as <repo>, and registers a Component entity that declares a dependsOn relation to the infra Resource.
  5. Terraform Cloud (or another runner) performs terraform apply for the new infra repo, provisioning the EC2 instance.
Below is a compact sequence illustration of these steps.
A diagram titled "Demo Steps" showing Infrastructure, Platform and Developer team icons on the left and a central form with Project Name "Demo-App" and Instance Type "t2.small." To the right are GitHub and YAML file icons labeled repos and Template.yaml representing the infrastructure code.

Roles and repositories

Use this quick reference for which team owns which repository: Example: here’s the Express API skeleton used as the app blueprint.
A screenshot of a GitHub repository page for "backstage-express-api-blueprint," showing a list of files and folders (e.g., .github/workflows, src, tests, package.json) and repository details like branches, commits, and language stats.
And this is the main organization infra repository that contains shared Terraform configuration other per-app infra will reference:
A GitHub repository webpage showing the repo header, branch info, a folder entry, and a large prompt to "Add a README" with a green button. The right sidebar displays repository stats and a language bar (HCL).

Example infra blueprint (ec2-infra-blueprint)

The infra blueprint accepts templated inputs:
  • name — project name used for resource naming.
  • instance_type — EC2 size chosen by the developer.
It references the infrastructure-IAC remote state to obtain a subnet ID. An example main Terraform module (simplified):
Resource entity for the EC2 instance (resource.yaml in the infra blueprint):

Template form and user experience

The template provides a multi-step Create flow in Backstage:
  • Project Info — component name and metadata.
  • Choose Location — repository location / owner.
  • Deploy EC2 — select instance size (e.g., t2.micro, t2.small, t2.medium).
Example Create flow UI:
Screenshot of a web interface titled "Create a new component" for a Node.JS App on EC2, showing a multi-step progress bar (Project Info, Choose a location, Deploy EC2, Review). The form displays repository location fields (host, owner, repository name) with Back and Next buttons.
Choosing an instance size:
A screenshot of a web UI titled "Create a new component" for provisioning a Node.JS app on EC2, showing progress steps and the "Deploy EC2" step. A dropdown of EC2 instance types is open with "t2.micro" highlighted and a cursor pointing at it.
High-level result: the template produces two repositories:
  • file-manager-service — application code (from the app blueprint).
  • file-manager-service-infra — Terraform code to provision the EC2 instance (from the infra blueprint).
Backstage will display the Component and Resource relations once both entities are registered.
A web dashboard titled "user-service" showing an Overview page with an About panel (owner "dev", lifecycle "experimental") on the left. On the right is a Relations graph linking "dev" to "user-service" and to "user-service-ec2."
A web dashboard page for a resource named "user-service-ec2" with an About panel describing it as an EC2 instance and links to source/techdocs. The right side shows a Relations graph illustrating dependencies between "user-service", "infra", and "user-service-ec2".

Template design — parameters and ordered steps

The single scaffolder template (nodejs-ec2-template) will:
  • Show a three-page form (project info, repo location, deploy EC2).
  • Execute the following steps, in order:
    1. fetch infra base (clone ec2-infra-blueprint into ./infra and provide values)
    2. publish infra (push ./infra to a new repo <repo>-infra)
    3. register infra Resource (catalog:register using resource.yaml)
    4. fetch app base (clone backstage-express-api-blueprint into ./code and provide values)
    5. publish app (push ./code to <repo>)
    6. register app Component (catalog:register using catalog-info.yaml)
    7. provide output links (Repository, Open in Catalog)
Below is a complete example Backstage Scaffolder template. Make sure your Backstage instance has the fetch:template, publish:github and catalog:register actions installed and configured.

Templatizing blueprints — key snippets

Infra blueprint: replace placeholders in main.tf and resource.yaml with scaffolder values. Example module block (templated):
Templatized resource.yaml:
App blueprint: update catalog-info.yaml so the Component depends on the infra Resource:

Note about Terraform execution

This example uses Terraform Cloud to detect new infra repositories and run terraform apply. If you do not use Terraform Cloud (or a similar runner), you must add an extra step that runs Terraform (for example, a CI workflow or a scaffolder action that executes terraform init and terraform apply) after publishing the infra repository.

Running the template

  • Add the nodejs-ec2-template YAML to your templates repo and let Backstage pick it up.
  • From the Backstage Create flow, select Node.js App on EC2, fill out project name, owner, repo location, and instance type, then run the template.
  • The template creates two Git repositories: <repo> (app) and <repo>-infra (Terraform).
  • Catalog registration will create a Component entity for the app and a Resource entity for the EC2 instance. The Component will declare a dependsOn relation to the Resource.
Example run completion UI:
A screenshot of a web dashboard showing a completed "Run of nodejs-ec2-template" with a horizontal progress bar of steps (Fetch Infrastructure base, Publish Infrastructure, Register, Fetch App Base, Publish App, Register App) each marked complete. There are buttons for "Repository" and "Open in Catalog" and a green mouse cursor pointing near the first step.

Post-run verification

  • Confirm the two GitHub repositories were created:
    • file-manager-service — app skeleton with templated catalog-info.yaml.
    • file-manager-service-infra — contains main.tf with name and instance_type set according to inputs.
  • In Backstage catalog, inspect the Component and Resource entities. The Component should depend on the file-manager-service-ec2 Resource and relations should be visible.
Example GitHub profile with created repos:
A screenshot of a GitHub profile page for "Sanjeev Thiyagarajan" with a large circular avatar on the left. The right side lists repositories (e.g., file-manager-service, user-service) with language tags, privacy labels, and star buttons.
Example resource and relation in Backstage:
Screenshot of a web dashboard for a resource titled "file-manager-service-ec2." The page shows an About panel (noting "EC2 instance for 'myapp'") and a Relations graph linking the entity to "file-manager-service" and "infra."
If Terraform Cloud (or your runner) performs the apply, you should see a running EC2 instance in AWS:
A screenshot of the AWS EC2 Instances console showing one running instance named "file-manager-service" (t2.micro) with 2/2 status checks passed. The left navigation pane lists EC2 sections like Instances, Images, and Elastic Block Store.

Summary and next steps

  • This pattern connects repository templating, GitHub publishing, Backstage catalog registration, and infrastructure provisioning.
  • You can extend it to provision other resource types (databases, load balancers, clusters) by creating additional infra blueprints and wiring them into the template steps.
  • Decide where Terraform should run (Terraform Cloud, CI runner, or a Backstage action) and update the scaffolder actions accordingly.
Useful links and references:

Watch Video

Practice Lab