Configuration Hierarchy
Backstage merges every --config file in the order it is passed on the command line. The merge is deep for objects and last-wins for single values: when two files set the same key, the later file wins. A list in a later file replaces the same list from an earlier file instead of merging with it. DevPortal 3.x assembles that --config chain from a base file plus a fixed set of product fragments.
The load order on a default install
On devportal-local 3.0.3 the backend starts with these files, in this order:
app-config.yamlapp-config.example.yamlapp-config.example.production.yamldynamic-plugins-root/app-config.dynamic-plugins.yaml(generated at boot from each enabled plugin'spluginConfig)app-config.veecode-auth.yamlapp-config.veecode-branding.yamlapp-config.extensions.yamlapp-config.veecode-product.yaml
A setting in a later file wins over the same setting in an earlier file. The product fragment loads last, so it overrides the earlier fragments.
Where your settings go on Kubernetes
On a Kubernetes install you add configuration through the devportal chart instead of mounting files. The chart accepts configuration through two values:
upstream.backstage.appConfigcarries the main operator configuration (application URLs, authentication, catalog locations).extraAppConfigadds ordered fragments. The chart ships entries for the auth, branding, extensions, and product fragments, with the product fragment last so it wins.
Because a list in a later file replaces the same list from an earlier file, repeat every entry you want to keep when you override a list such as catalog.locations.
Where your settings go on the local stack
The local stack derives its files from the pinned chart. Do not edit them. Add a separate fragment file and pass it with --config after the product fragment, as described in Add a configuration fragment. The same replacement rule applies: a list in your fragment replaces the same list from an earlier file.
Environment variables
Configuration values may reference process environment variables with ${NAME} syntax. Backstage resolves them from the process environment at startup, after all --config files are merged.
On the local stack, APP_CONFIG_app_baseUrl and APP_CONFIG_backend_baseUrl set the portal and backend URLs using DEVPORTAL_PORT:
APP_CONFIG_app_baseUrl: "http://localhost:${DEVPORTAL_PORT:-7007}"
APP_CONFIG_backend_baseUrl: "http://localhost:${DEVPORTAL_PORT:-7007}"
Related
- Add a configuration fragment — the local-stack procedure for adding a fragment.
- Dynamic Plugins — how
app-config.dynamic-plugins.yamlin position 4 is built. - Composing a Portal — how configuration relates to plugin loading and entity annotations.
Was this helpful?