Cheat notes · Module 02 · The portal and its catalog
Configuration, secrets and Postgres
A five-minute review for when you have done this module and want it back in your head. Open the full module for the steps and the lab, or the full text to print.
The idea
Everything is configuration: one YAML file in Git with placeholders, the values from the environment. Config files layer (objects merge, lists replace), secrets never reach Git or the browser, and scripts call the API with a configured token.
Remember
- Config layers:
app-config.yaml, thenapp-config.local.yamlif present, or the files given with--config. Later files override keys. Lists are replaced, not merged. - Environment variables:
${POSTGRES_PASSWORD}is read at backend start;${POSTGRES_HOST:-localhost}has a default. A missing value is only an error when a plugin needs it. - Frontend visibility: each plugin's config schema marks what the browser may see. Secrets are never sent.
- External access: scripts and CI call the API with a token in
backend.auth.externalAccess; each token has asubject, so logs show who called. - Postgres: one database per plugin (
backstage_plugin_catalog,backstage_plugin_scaffolder, ...). .envstays on your laptop and is git-ignored.yarn startdoes not read it: load it withset -a && . ./.env && set +ain every terminal.
Pitfalls
- A typo in a variable name on a fresh laptop:
Missing required config value at 'backend.auth.externalAccess[0].options.token'and the backend shuts down. Plainconfig:checkpasses;--strictcatches it. Keep a.env.examplewith every name. - A variable left over in your shell from an earlier session hides the same mistake. Test from a fresh terminal.
- Pasting
config:print --with-secretsoutput anywhere.
Commands
set -a && . ./.env && set +a | Load .env into this terminal |
yarn backstage-cli config:print --frontend | What the browser receives |
yarn backstage-cli config:print | The backend view, secrets shown as <secret> |
yarn backstage-cli config:check --strict | Fail on a missing required value, not only on a wrong shape |
curl -H "Authorization: Bearer $PORTAL_API_TOKEN" localhost:7007/api/catalog/entities | Call the API as a script |
git check-ignore .env | Prove Git ignores the secrets file |
Placeholders in app-config.yaml
backend:
auth:
externalAccess:
- type: static
options:
token: ${PORTAL_API_TOKEN}
subject: portal-cli
database:
client: pg
connection:
host: ${POSTGRES_HOST:-localhost}
password: ${POSTGRES_PASSWORD}
Test yourself
Answer in your head first, then open the answer.
You set catalog.locations in app-config.local.yaml. What happens to the list in app-config.yaml?
It is replaced. Lists in a later file replace the whole list; objects merge.
Why is the database password safe in app-config.yaml?
The file only holds ${POSTGRES_PASSWORD}. The value comes from the environment and is never sent to the browser.
What does config:check --strict add?
It fails when a required value is missing, not only when the shape is wrong.
Where module 02 leaves you: The portal is called Acme Portal, stores its data in Postgres in Docker, and accepts a static API token from .env. The config change is merged in your portal repo; .env is not in Git.