PlatformEngr® Backstage course

Module 01 · The portal and its catalog · 45 min · You are: Platform team

Create the app and find your way around

In this module

  • You learn: What create-app generates, how the frontend and backend are wired, and where each thing you see in the UI comes from in the code.
  • You do: Generate the app, push it to GitHub, start it, find four things in the UI, then find them again in the code and the API.
  • You end with: A portal repo on GitHub with the generated app, running on your laptop at http://localhost:3000 with example data and guest sign-in.

You will change this app every week for years, so start by knowing where things live. The generated app is small: one file wires the frontend, one wires the backend, one YAML file configures both. Everything else is npm packages. Learn to go from "I see this in the UI" to "this line adds it".

Open this module in the interactive course to track progress.

Concepts

The monorepo
packages/app (the React frontend), packages/backend (the Node backend), plugins/ (your own plugins), app-config.yaml (config for both). Yarn workspaces tie them together.
Backend plugins
The backend is one process. packages/backend/src/index.ts adds each plugin with backend.add(import(...)). Each plugin serves its own API under /api/<pluginId>.
Frontend features
The app is built from extensions: pages, nav items, entity tabs. Installed plugin packages are discovered automatically (app.packages: all); App.tsx adds the rest.
Pinned version
create-app 0.9.3 generates Backstage 1.56.0. The release is recorded in backstage.json; module 09 upgrades it.

Files to know

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

Steps

1. Generate the app

This downloads the generator and runs yarn install, which takes 5 to 10 minutes the first time.

The command that creates your portal. When it asks Enter a name for the app, type portal. It finishes with Successfully created portal.

cd ~/work && npx @backstage/[email protected] --path portal

2. Put it on GitHub

This is the platform team's repo. The generator already made a first commit; name the branch main and push it.

cd ~/work/portal && git branch -M main
gh repo create YOUR_GITHUB_USER/portal --public --source . --push

3. Start the portal

One command starts both halves: the frontend on port 3000 and the backend on port 7007.

Warning. This terminal is the portal. Leave it running. It prints every backend log line, and it restarts the right half when you save a file. Use a second terminal for everything else.

cd ~/work/portal && yarn start

After about a minute your browser opens http://localhost:3000. You see a sign-in page with one option, Guest: click Enter. Guest sign-in is for local development only; module 05 replaces it.

4. Find four things in the UI

Find each item and check you see what is described.

1. A component. The catalog is the first page. Click example-website. The Overview tab shows its owner (guests) and system (examples).

2. Where it came from. On the same page, open the menu (⋮, top right) and choose Inspect entity, then Raw YAML. Find the annotation backstage.io/managed-by-location: it points at examples/entities.yaml in your repo.

3. The actions templates can run. Click Create in the sidebar, then the Actions tab. Find fetch:template and publish:github: these are steps a template can use.

4. What the frontend is made of. At the bottom of the sidebar, under your avatar, click Visualizer, then the Text tab. It lists every extension in the app, for example page:catalog. Each page you used is one of these.

5. Find the same things in the code

Every item has a line behind it. Open Quick look on the files above as you go.

1 and 2. The catalog reads examples/entities.yaml because app-config.yaml lists it under catalog.locations. Expect three locations, all under examples/:

cd ~/work/portal && grep -n "target:" app-config.yaml

3. Actions belong to the scaffolder backend plugin and its modules. Expect plugin-scaffolder-backend and two scaffolder-backend-module-* lines:

grep -n "scaffolder" packages/backend/src/index.ts

4. The catalog page is an extension from an npm package. app-config.yaml moves it to / (the site root) by its id, page:catalog:

grep -n -A2 "page:catalog" app-config.yaml

6. Call the API

Each backend plugin serves an API under /api/<pluginId>. The UI uses it; so can scripts.

Ask the catalog for its entities without credentials. Expect 401: every request needs a token, even on your laptop. Module 02 gives scripts one.

curl -s -o /dev/null -w "%{http_code}\n" localhost:7007/api/catalog/entities

Simplified for the course

The app uses an in-memory SQLite database and example data, so everything resets when the backend restarts. Module 02 moves to Postgres.

Break it on purpose: Remove a backend plugin

A platform engineer tidies the backend. The scaffolder line looks unused ("nobody has created anything yet"), so they comment it out. The portal starts fine.

You practise: telling a frontend problem from a backend one, and following a page back to the plugin that serves it.

1. Break it

Change in ~/work/portal/packages/backend/src/index.ts
The tidy-up.

- backend.add(import('@backstage/plugin-scaffolder-backend'));
+ // backend.add(import('@backstage/plugin-scaffolder-backend'));

Save. The backend restarts by itself (watch the portal terminal). Then in the browser: Create, and Choose on Example Node.js Template.

2. What you see

Expected: the template form. You get: a red message, Failed to load template, ResponseError: Request failed with 404 Not Found.

The template list still shows: it comes from the catalog, not the scaffolder. Only the part that runs templates is gone.

3. Fix it yourself

Find which backend API the page calls, prove it is missing, and bring it back. You are done when Choose opens the form again.

Hint 1

A 404 from the backend means nothing answers that path. Which plugin serves /api/scaffolder? Try curl -s -o /dev/null -w "%{http_code}\n" localhost:7007/api/scaffolder/v2/actions: 404 means no plugin, 401 means a plugin that wants a token.

Hint 2

Look at the scaffolder lines in packages/backend/src/index.ts. The modules are still there; the plugin they extend is not.

The fix

Change in ~/work/portal/packages/backend/src/index.ts

- // backend.add(import('@backstage/plugin-scaffolder-backend'));
+ backend.add(import('@backstage/plugin-scaffolder-backend'));

Save, wait for the restart, and check. Expect 401 (the plugin is back and wants a token), not 404:

curl -s -o /dev/null -w "%{http_code}\n" localhost:7007/api/scaffolder/v2/actions
After you fixed it: the five questions
What failed?
The scaffolder backend plugin was not loaded, so every /api/scaffolder call returned 404.
How was it detected?
An error when choosing a template. The template list still worked, because it comes from the catalog.
Who responds?
The platform team.
How is it corrected?
Put the backend.add line back.
How is it prevented?
Changes to packages/backend/src/index.ts go through review, and a smoke test calls each plugin's API after deploy (401 is alive, 404 is missing).

Quiz

  1. Where is a backend plugin turned on?
    • A backend.add(import(...)) line in packages/backend/src/index.ts
    • A checkbox on the Settings page that the platform team sees after signing in
    • Any package listed in the root package.json is started automatically
  2. Why does curl localhost:7007/api/catalog/entities return 401 on your laptop?
    • The catalog is empty, and an empty catalog answers 401 instead of an empty list
    • Every backend request needs a token, from a user, another plugin or a configured script
    • Port 7007 only accepts requests that come from the frontend on port 3000
  3. The template list shows, but Choose fails with 404. Where is the problem?
    • The template YAML, which must have a syntax error
    • The catalog, which has lost the template
    • The backend: the plugin that serves /api/scaffolder is not loaded
Answers
  1. A backend.add(import(...)) line in packages/backend/src/index.ts Installed packages do nothing in the backend until they are added.
  2. Every backend request needs a token, from a user, another plugin or a configured script Backstage authenticates every request by default. Scripts get a token in module 02.
  3. The backend: the plugin that serves /api/scaffolder is not loaded The list comes from the catalog; running a template needs the scaffolder backend.

Field note

The fastest debugging habit I teach for Backstage: open the browser's network tab and read the failing URL. /api/<pluginId>/... tells you which backend plugin to look at, and 401, 403 and 404 each point somewhere different.

Report a problem with this module