Certified Backstage Associate common mistakes
Certified Backstage Associate · Understand the traps and how to avoid them.
Editing files under node_modules or a scaffolded plugin's dist/ output when trying to change a template or component, instead of editing the package source under packages/ or plugins/, then wondering why changes vanish after the next yarn install or build.
Candidates coming from a quick-start tutorial treat the running app directory as the source of truth; Backstage is a monorepo where the app (packages/app, packages/backend) consumes workspace packages, so generated and vendored directories are overwritten.
What to do instead
Always locate the owning workspace package (plugins/ for frontend, plugins/-backend for backend) and edit its src/ files; run yarn tsc and restart the dev server to verify the change survives a rebuild.
Registering a component in the catalog with a catalog-info.yaml whose metadata.name collides with an existing entity, or omitting spec.type/spec.lifecycle, and then debugging the wrong layer when the entity does not appear.
Candidates assume any YAML the catalog accepts will show up, but entity references are keyed by kind/namespace/name, and required fields for Component kind are enforced; a duplicate name silently updates or rejects the entity depending on processor order.
What to do instead
Use a unique, lowercase, DNS-compatible metadata.name, include spec.type and spec.lifecycle, and inspect the catalog processing log plus the entity's own page for validation errors before touching code.
Treating the catalog as a live view of the Git repository and expecting file edits to appear immediately, rather than understanding that entities are ingested by processors and refreshed on a schedule or on demand.
The catalog is a database populated by entity providers and processors; candidates conflate the source location with the stored entity and are surprised when changes lag or when a deleted file leaves a stale entity.
What to do instead
Learn the processing pipeline (location -> reader -> processor -> stitcher -> database), trigger a manual refresh from the entity page or the catalog API, and check the refresh interval configuration.
Writing a custom processor or entity provider that mutates the incoming entity in place and returns it, instead of returning a new entity, causing subtle cross-entity contamination or dropped relations.
Candidates reuse patterns from simple map functions; Backstage processors are expected to be pure with respect to their input, and shared object references leak state between entities in the same batch.
What to do instead
Clone the entity (for example with structuredClone or a spread of the relevant nested objects) before modifying, return the new object, and add unit tests that process two entities in sequence and assert independence.
Putting secrets, tokens, or environment-specific URLs directly into app-config.yaml and committing it, instead of using app-config.local.yaml or environment variable substitution.
Tutorials show a single app-config.yaml, so candidates edit it for local credentials; Backstage merges app-config.yaml, app-config.local.yaml, and app-config..yaml, and the local file is gitignored by convention.
What to do instead
Keep shareable defaults in app-config.yaml, put secrets in app-config.local.yaml (or inject via ${ENV_VAR} substitution), and confirm the merge order so the local override actually wins.
Misconfiguring the backend baseUrl and frontend backend.baseUrl so the frontend calls the wrong origin, producing CORS errors or 404s on /api paths that candidates then chase in plugin code.
The frontend resolves backend plugin routes relative to backend.baseUrl, and the backend's own baseUrl affects generated links and auth callbacks; candidates set only one of them or leave localhost defaults in a deployed config.
What to do instead
Set backend.baseUrl to the externally reachable backend origin and frontend.baseUrl to the app origin in the environment's config, then verify by inspecting the network tab for the actual request URL.
Assuming a new frontend plugin is automatically routable and its backend counterpart automatically mounted, without registering the route in the app and the router in the backend.
Backstage uses explicit composition: the app's FlatRoutes (or Route entries) and the backend's index/router registration must reference the plugin; scaffolding creates the package but not the wiring in every case.
What to do instead
Add the plugin's page to the app's route tree and register the backend plugin's router in packages/backend/src/index.ts, then confirm the route path matches what the plugin's API client expects.
Building a custom scaffolder template that references parameters without declaring them in the template's parameters schema, or using actions whose inputs do not match the installed action versions.
Template parameters are validated against the declared schema, and action input schemas are version-specific; candidates copy snippets from different Backstage releases and get opaque task failures.
What to do instead
Declare every parameter in the template's parameters block with type and description, run the template in dry-run where possible, and check the task's step logs for the exact action input validation error.
Confusing the two customization layers: using a theme or component override to try to change backend behavior, or editing the app's theme to change how a third-party plugin renders without using its exported extension points.
Backstage customization is split between the app (themes, sidebar, routes, component overrides via the app's APIs) and plugins (extension points, APIs, and config schema); candidates pick whichever file they found first.
What to do instead
Decide first whether the change is app-shell, plugin UI, or backend; use the plugin's documented extension points or override the API implementation via createApiFactory rather than forking the plugin.
Running the backend with the wrong Node version or skipping yarn install after changing a package's dependencies, then diagnosing plugin resolution errors as code bugs.
Backstage has a supported Node major version and a strict workspace dependency graph; a stale node_modules or mismatched Node breaks module resolution in ways that look like application errors.
What to do instead
Pin the documented Node version (for example via .nvmrc), run yarn install at the repo root after any package.json change, and use yarn tsc plus a clean dev-server restart as the first diagnostic step.