PlatformEngr® Backstage plugins course

Module 00 · Orientation · 20 min · You are: Platform and product

Orientation: how a Backstage plugin is built

In this module

  • You learn: Plugins, modules, services and extension points in the backend; plugins, extensions and blueprints in the frontend; and why one plugin is four or more packages.
  • You do: Read three files from the reference repo, check your tools, and start the portal you finished in the first course.
  • You end with: Your portal runs on your laptop with Postgres, the catalog knows checkout, and the reference repo is up to date.

In the first course you configured Backstage from the outside. Now you write code that runs inside it. Backstage gives plugin code a small set of building blocks with strict rules: a backend plugin only gets what it asks for, and a frontend plugin is a list of extensions the app plugs in. Learn the blocks first and every plugin you read, including the official ones, looks the same.

Open this module in the interactive course to track progress.

Concepts

Backend plugin
One feature with its own API under /api/<pluginId> and its own database. It declares the services it needs (logger, database, scheduler) and gets them injected. Backend system.
Module and extension point
A module adds to one plugin without changing its code, through an extension point the plugin offers. Your platform team owns the plugin; other teams own modules.
Frontend plugin
A list of extensions: a page, an API client, an entity card. Each is made from a blueprint and attaches to a place in the app. Frontend system.
Package roles
readiness-backend (the server), readiness (the UI), readiness-common (types and permissions both use), readiness-node (what backend modules import). Plugin structure.
The readiness plugin
A production-readiness scorecard: each component gets checks (has an owner, has docs, links a runbook) and a score. Teams see it on their entity page and add their own checks.

Who owns what in this course

ThingPackageOwner
The readiness API, storage and scheduleplugins/readiness-backendPlatform team
Shared types and permissionsplugins/readiness-commonPlatform team
The extension point for new checksplugins/readiness-nodePlatform team
The page, card and tabplugins/readinessPlatform team
A check only team-checkout needsplugins/readiness-backend-module-apiteam-checkout
Who may evaluateplugins/permission-backend-module-acmePlatform team

Everything lives in the portal repo. A team that owns a module owns its folder and reviews its changes (a CODEOWNERS line in a real repo).

Files to know

Where you are heading. Click Quick look on each file: it opens the finished reference file with numbered circles on the lines that matter.

Open them in your editor or on GitHub; the bullets say what to look at.

Steps

1. Tell the course who you are

The same GitHub user and folder as in the first course. If you set them there, they are already filled in.

Set your GitHub user and workspace folder in the interactive course or the form at the top of the notes index; these notes then show your values.

2. Check your tools

Each tool reports ok, MISSING or PROBLEM. Fix what it reports and run it again until it says All set.

check() {  # tool, works-check, version, problem, where-to-get-it, optional
  if ! command -v "$1" >/dev/null 2>&1; then
    if [ -n "$6" ]; then printf '  optional  %-22s not installed (%s)\n' "$1" "$5"
    else printf '  MISSING   %-22s install it: %s\n' "$1" "$5"; bad=$((bad+1)); fi
  elif ! eval "$2" >/dev/null 2>&1; then printf '  PROBLEM   %-22s %s\n' "$1" "$4"; [ -n "$6" ] || bad=$((bad+1))
  else printf '  ok        %-22s %s\n' "$1" "$(eval "$3" 2>&1 | head -n 1)"; fi
}
bad=0
check 'git' 'git --version' 'git --version' 'installed, but it does not run' 'https://git-scm.com/downloads'
check 'node' "node -v | grep -Eq '^v(22|24)[.]'" 'node -v' 'found, but Backstage 1.56 needs Node.js 22 or 24' 'https://nodejs.org/en/download'
check 'yarn' 'yarn --version' 'yarn --version' 'installed, but it does not run' 'https://yarnpkg.com/getting-started/install (or: corepack enable)'
check 'docker' 'docker info' "docker version --format '{{.Server.Version}}'" 'installed, but the Docker daemon is not running: start Docker Desktop (or the docker service)' 'https://docs.docker.com/get-docker/'
check 'gh' 'gh auth status' 'gh --version' 'installed, but not logged in: run gh auth login' 'https://cli.github.com/'
check 'jq' 'jq --version' 'jq --version' 'installed, but it does not run' 'https://jqlang.org/download/'
check 'curl' 'curl --version' 'curl --version' 'installed, but it does not run' 'your package manager (it ships with macOS and most Linux distributions)'
if [ "$bad" -eq 0 ]; then echo "All set: every tool is ready."; else echo "$bad tool(s) need attention. Install or fix them, then run this check again."; fi

3. Update the reference repo

You copy a few long files from it. Pull the latest, or clone it if you no longer have it.

git -C ~/work/backstage-workshop pull -q || git clone -q https://github.com/platformengr/backstage-workshop.git ~/work/backstage-workshop

The plugin packages are in portal/plugins. Expect readiness, readiness-backend and five more:

ls ~/work/backstage-workshop/portal/plugins

4. Start your portal

This course builds on the portal repo from the first course. Start Postgres and the portal the way you left them.

docker start portal-db
cd ~/work/portal && git switch -q main && git pull -q && yarn install

Warning. This terminal is the portal. Leave it running. Use a second terminal for everything else.

cd ~/work/portal && set -a && . ./.env && set +a && yarn start

Sign in with GitHub. In a second terminal, check that the catalog knows checkout and its owner. Expect team-checkout:

cd ~/work/portal && set -a && . ./.env && set +a
curl -s -H "Authorization: Bearer $PORTAL_API_TOKEN" localhost:7007/api/catalog/entities/by-name/component/default/checkout | jq -r .spec.owner

Simplified for the course

All packages live in the portal repo. Larger companies publish shared plugins from their own repos to a private npm registry.

Quiz

  1. team-checkout needs one extra readiness check. Where does their code go?
    • A backend module that adds the check through the plugin's extension point
    • A pull request that edits the readiness plugin's list of checks directly
    • A second copy of the readiness backend plugin with the extra check added
  2. Which package holds the types both the frontend and the backend use?
    • readiness-backend, because it creates the data the frontend shows
    • readiness-common, which both sides can import
    • readiness-node, because types are compiled by Node
  3. How does a backend plugin get a database connection?
    • It reads the Postgres password from app-config.yaml and connects itself
    • It imports the database client from the catalog plugin
    • It declares the database service as a dependency and gets one injected
Answers
  1. A backend module that adds the check through the plugin's extension point Modules extend a plugin without changing it, so each team owns its own code.
  2. readiness-common, which both sides can import A frontend plugin must never import a backend package; -common is safe for both.
  3. It declares the database service as a dependency and gets one injected Services are injected. The backend decides how they are built; the plugin only asks.

Field note

When I review plugin code, the first thing I look at is the list of services in registerInit. It tells me in ten lines what the plugin can touch: the database, the catalog, the network. Keep that list honest.

Report a problem with this module