Skip to content
Latchkey

Backstage app-config.yaml ${...} env substitution missing in CI

Backstage substitutes ${ENV_VAR} references in app-config.yaml from the process environment. In CI those variables come from secrets or step env, and a missing one leaves the value empty, breaking startup, database, or integrations config.

What this error means

The backend fails to read config, or a downstream feature (database, auth, integration) fails because a "${...}" placeholder resolved to an empty string.

backstage
Backend failed to start up Error: Failed to initialize database connection:
missing password
    at DatabaseManager ...
# app-config.yaml referenced ${POSTGRES_PASSWORD} but the env var was unset

Common causes

The referenced env variable is not set in the job

app-config.yaml uses ${POSTGRES_PASSWORD} or ${BACKEND_SECRET}, but the workflow never exported it, so substitution yields empty.

A secret was not passed to the step

The value lives in a repository secret that was not mapped into the step env, so the process cannot see it.

How to fix it

Export the referenced variables from secrets

  1. List every ${VAR} used in your app-config files.
  2. Map each to a secret or value in the step env.
  3. Re-run so substitution resolves to real values.
.github/workflows/ci.yml
env:
  POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
  BACKEND_SECRET: ${{ secrets.BACKEND_SECRET }}

Provide a CI-specific config with defaults

Use an app-config.local or CI overlay that supplies safe values so substitution never yields empty for non-secret fields.

Terminal
yarn start --config app-config.yaml --config app-config.ci.yaml

How to prevent it

  • Keep an inventory of every ${VAR} used in app-config files.
  • Map required secrets into the step env for jobs that read config.
  • Fail fast with a config lint that flags unset substitutions.

Frequently asked questions

What causes "app-config ${...} not substituted"?
app-config.yaml uses ${POSTGRES_PASSWORD} or ${BACKEND_SECRET}, but the workflow never exported it, so substitution yields empty.
How do I fix app-config ${...} not substituted?
Export the referenced variables from secrets

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card