Why custom Backstage plugins break on upgrade and who should own the fix
Custom plugins break on upgrade because they depend on Backstage core APIs, and those APIs change on a fixed schedule. The Backstage main release line ships monthly, on the Tuesday before the third Wednesday of each month, and the next release line ships weekly on Tuesdays. Each release can rename, move or remove the interfaces your plugin imports, so a plugin that worked on one version may fail to build or load on the next. The team that wrote the plugin owns its compatibility, not the platform team and not the Backstage project. That team should decide which release line it follows, keep a named owner for each internal plugin, and treat every core upgrade as a change that touches its code.
The supported path is to move the app and its plugins together. Use yarn backstage-cli versions:bump to move all @backstage packages to the same release, including the packages your plugins declare, so that no plugin is left pinned to an older core. Then read the changesets and the template changes in the Upgrade Helper, and apply the changes to your plugin source before you publish or deploy it. Check the Node.js version too: Backstage supports exactly two adjacent even-numbered Node.js releases, and as of Backstage 1.46.0 these are Node.js 22 and 24. If your plugin ships native modules or depends on a Node.js feature, confirm it works on both supported releases before you upgrade the runtime.
Plan the upgrade work as a recurring cost, not a one-off project. Each plugin needs a test run against the new release in a non-production environment before it reaches users, and the plugin owner should sign off the result. The latest release listed on the Backstage GitHub releases page at the time of writing was v1.55.3, published September 29, 2026, with 1.56.0 in the next release line, so confirm the current versions before you schedule work. Security fixes can arrive on the release line you run: the versioning policy says high and critical severity vulnerabilities will always be backported to releases from the last 6 months if feasible, so an app that falls behind may need to move sooner than planned. Ask each plugin owner to name the release they target and the date by which they will test it.
Which core changes affect custom plugins
This table compares the core Backstage changes most likely to break an internal plugin, what each change means for your code, and the action to take. Read each row as a checkpoint for every upgrade, and confirm the specifics against the release notes for the version you are moving to.
| Core change | Impact on custom plugins | Action needed |
|---|---|---|
| Monthly main and weekly next release lines | Plugins built against the next line can break more often because it ships weekly, while the main line ships monthly | Pick one release line per upgrade cycle, and test plugins against the target version before adopting it |
| Security backports to recent releases | Fixes for high and critical vulnerabilities are backported to releases from the last 6 months where feasible, so a patch may arrive without a full version bump | Track which release line you are on, and confirm your plugins still build after applying backported patches |
| Two supported Node.js releases (22 and 24 as of 1.46.0) | Plugins with native modules or Node-specific APIs may fail when the runtime changes | Confirm the Node.js version your plugin build and CI use matches the supported pair for your target release |
| Coordinated @backstage package bumps via versions:bump | A plugin that pins its own @backstage versions can fall out of step with the app and backend | Keep every @backstage dependency in your plugin on the same version set, and bump them together |
| Deprecated packages such as @backstage/backend-common | Plugins importing deprecated APIs may stop building or lose support, and replacement APIs may differ in shape | Confirm each deprecated import against the target release notes, then move to the named replacement |
| Legacy backend system to new backend system extension points | Plugins registered through legacy plugin wiring need to expose extension points or module registrations in the new model | Confirm the target release notes for the new backend extension points, and plan a rewrite of plugin registration code |
| Plugin API and frontend changes between releases | Changed exports, props or routing can silently alter plugin behavior even when the build passes | Run plugin unit tests and a smoke test in a staging portal before promoting the upgrade |
Preparing plugin inventory, tests and a backup before the bump
Plugin compatibility problems are cheapest to find before the version change starts. The four cards below cover what you need on paper, in code and in storage before anyone runs the bump, and the sign-off that makes the work someone's responsibility.
Inventory every internal plugin
List each internal plugin, its frontend and backend packages, and every @backstage dependency with its current version. Record which extension points and service APIs each plugin calls, because those are the surfaces most likely to change between releases. Note which plugins have no active owner, since they will stall the upgrade later. Keep the list in version control next to the app so it can be diffed after the bump.
Build a list of deprecated imports
Search every internal plugin for imports from packages the Backstage project has deprecated, such as @backstage/backend-common, and for usage of APIs marked for removal in release notes. Group findings by plugin and by owner so each team knows what it must change. Treat a deprecated import as a task with a named file, not a general warning, and decide before the bump which replacement package each one will use.
Run a test environment on the target version
Create a separate environment that runs the target Backstage version with your plugins, configuration and a copy of the catalog, and run the plugin test suites there. Include backend tests that exercise your plugin routes, since frontend tests alone miss many API changes. Confirm which Node.js version the target release expects before you start, because a plugin can fail on runtime differences that have nothing to do with Backstage code.
Back up PostgreSQL and tag the app
Take a PostgreSQL backup of the Backstage databases before any schema-affecting change, and test that you can restore it into a scratch instance. Tag the current app repository in git so you can return to the exact pre-upgrade code and lockfile. Backstage gives each backend plugin its own logical database, so confirm the backup covers all of them, not only the main one. Record the tag name and backup identifier in the change ticket.
Get named owners to sign off
Assign a named owner to each internal plugin who reviews the inventory, the deprecated-import list and the test results, and signs off in writing before the production change. Owners should also agree who fixes a plugin that fails after the bump and how long the portal can run with that plugin disabled. Without this step, plugin fixes tend to fall to the platform team by default and stall the release.
How plugin type changes the compatibility work
Frontend plugins run in the browser and call the Backstage frontend APIs, the component library and any backend endpoints they consume. Upgrades usually change component props, routing, the API utility references and the shape of the frontend system that your plugin registers with. Most breakage shows up as build errors or as a page that renders blank, so the failure is often visible quickly but the root cause can be spread across several imports.
- Imported APIs: Check every import from
@backstage/*packages, since renamed or relocated exports are the most common build failure. - Component props: Review Material UI and Backstage component usage in each page, especially tables, cards and dialogs.
- Route and extension wiring: Confirm routes, extension points and nav items still register and appear in the sidebar.
- Backend calls: Exercise each API request the UI makes against the upgraded backend to catch changed response shapes.
- Browser checks: Run the plugin in a browser on the new version, including sign-in and empty-state views.
After the bump, open each custom page in a browser with a real catalog entity and confirm it loads without console errors.
Backend plugins written against the legacy service APIs depend on @backstage/backend-common and the older service factories for logging, configuration, database access and authentication. Backstage has deprecated backend-common, so these plugins need to move to the replacement core packages and service interfaces before the deprecated package is removed from the release you target. Problems tend to appear at startup, when a plugin fails to register its router or reads configuration through a changed interface.
- Deprecated imports: Find every use of
backend-commonand map each helper to its current replacement in the upgrade notes. - Database access: Confirm that the plugin still receives its own logical database through Knex and that migrations run on a copy of production-like data.
- Auth and identity: Check token validation and any calls to other plugins, because service-to-service auth changed with the newer packages.
- Configuration reads: Verify each configuration key the plugin reads still resolves, including defaults and secrets.
- Startup and routes: Start the backend locally and call each route to confirm registration and responses.
Run the plugin's integration tests against a database built from the new migrations before promoting the change.
Plugins built on the new backend system register through extension points and modules instead of wiring services by hand. Upgrades in this model usually affect extension point names, the signatures of registration functions, and the order in which modules initialize. Because the framework loads plugins as separate pieces, a change in one extension point can silently disable a feature that another module depends on.
- Extension point signatures: Compare each
registerExtensionPointcall and the methods your module calls against the release notes for the target version. - Module dependencies: Confirm that every module your plugin depends on is still installed and that its dependencies resolve during startup.
- Initialization order: Check that code relying on another module's initialized state still runs after the upgrade.
- Plugin discovery: Verify the backend index file still loads each plugin and module into the backend instance.
- Feature parity: Test each action the extension point exposes, such as catalog processors or scaffolder actions, not just startup.
Write a test that loads the backend with your plugin and checks that each extension point is registered before you rely on a green build.
Some plugins depend on packages that have moved out of the core Backstage repository into the community-plugins repository. These packages can change their package names, release cadence and maintenance status independently of the core release line. A version that works with one core release may not match the next, and an abandoned package can block an upgrade even when your own code is clean.
- Package names: Confirm each dependency still resolves to a current package name in the community repository.
- Version alignment: Check that the community package version matches the Backstage release you are moving to.
- Maintenance status: Review the package's recent commits, open security issues and whether maintainers still respond.
- Transitive changes: Run
yarn whyon shared dependencies to see whether a community package pulls in a conflicting version of a core library. - Fallback plan: Note whether you can fork, replace or remove the package if it stops tracking Backstage releases.
Before you commit to an upgrade date, confirm that every community dependency publishes a version compatible with your target release.
Upgrade sequence for custom plugins, with checks and rollback points
This sequence moves your internal Backstage plugins to a new release in a controlled order, so each change has a named check and a point you can return to. It ends with a promoted release that has passed catalog and scaffolder verification against a copy of production data.
Freeze plugin changes and tag the baseline
The plugin owners agree a freeze on feature work and merges to the internal plugin repositories for the upgrade window. The platform lead tags the current main branch and records the running image digest in production, so the baseline is known before anything changes. Done means the tag exists, the digest is written in the upgrade ticket, and every plugin owner has confirmed the freeze in writing. Rollback at this point is simply leaving production untouched.
Run versions:bump on a dedicated branch
An engineer creates an upgrade branch and runs yarn backstage-cli versions:bump so every @backstage package moves together to the target release. The lockfile diff and the list of changed packages are reviewed by the platform team. Done means the branch installs cleanly and the bump commit is isolated from any plugin code edits. Rollback is deleting the branch, since the baseline tag is untouched.
Apply Upgrade Helper changes to plugin packages
Using the Backstage Upgrade Helper for the same version pair, each plugin owner applies the template changes to their own plugin packages, including changes to package.json peer dependencies and imports that have moved. Deprecated packages such as @backstage/backend-common should be replaced with the packages the release notes name, and any extension point usage should be checked against the new API. Done means each plugin has a commit that references the helper change list and the owner has noted any change they chose not to make. Rollback is reverting that plugin's commit on the branch.
Fix type and build errors
The engineers run the TypeScript type check and the build for the app and every custom plugin, then fix errors caused by changed interfaces, removed exports or new required options. Each fix is kept in a small commit tied to the error it resolves, so a reviewer can trace it. Done means the full build passes with no suppressed errors added to get past the check. Rollback is reverting individual fix commits, which is why small commits matter here.
Run plugin unit and integration tests
Each plugin's unit tests run first, then its integration tests against a local PostgreSQL database and the upgraded backend. Plugin owners check that tests which mock core APIs still reflect the new behavior, since a passing mock can hide a changed signature. Done means the suites pass on the upgrade branch and any skipped test has a linked ticket. Rollback is the same as the previous step: revert the commit that introduced the failure and rerun the suite.
Deploy to staging with a production database copy
The upgraded image is deployed to a staging environment that uses a copy of the production database, with the same authentication and catalog configuration. Database migrations run against the copy first, and the migration output is saved with the ticket. Done means the staging portal starts, the migrations complete, and the copy's restore time and source snapshot are recorded. Rollback is redeploying the baseline image digest to staging and discarding the copy.
Verify catalog and scaffolder actions
Testers check that catalog entities from each internal plugin still load, that entity relations and ownership display correctly, and that every custom scaffolder action runs end to end on a test template. They also confirm that any custom plugin API responds for an authenticated user. Done means a written checklist with each plugin and each action marked pass, with any failure linked to a fix or an accepted risk. Rollback is returning staging to the baseline image and fixing the failing plugin before retesting.
Promote the release and keep the rollback image
After the staging checklist passes and the owners sign off, the same image built from the upgrade branch is promoted to production during an agreed change window. The previous image digest and the baseline tag stay available for the rollback period you set in advance. Done means production runs the promoted digest, the catalog and scaffolder checks are repeated in a short smoke test, and the change record links every commit and test result. Rollback is redeploying the recorded baseline digest, which the team should rehearse before the window opens.
What makes plugin upgrades take longer
How many internal plugins does an upgrade have to cover?
The count of internal plugins is the most direct driver, because every plugin needs its own dependency bump, build, type check and test run. Each plugin also has its own frontend or backend wiring that may change between releases. A portal with a handful of plugins that share one code style is usually a small job, while a portal with dozens of plugins across several repositories multiplies the review and testing work. Ask any partner to list every plugin, its package type (frontend, backend, common or module) and its owner before estimating. Plugin count is a one-time driver for the first upgrade and a recurring one for every monthly release that touches them.
Do deprecated or removed APIs make Backstage plugin upgrades harder?
Yes. Deprecated packages such as @backstage/backend-common and older helper APIs force code changes that cannot be done by a version bump alone, and each removed API adds a rewrite of the call sites that use it. The effort depends on how deep those calls go into your code, so search your plugins for imports of deprecated packages and count the call sites before the work starts. Plugins that already moved to the newer packages carry much less risk. The Backstage Upgrade Helper shows template changes, but it does not rewrite your custom code for you.
How do custom extension points affect plugin upgrade effort?
Custom extension points and plugin-to-plugin contracts raise effort because they depend on internal interfaces that Backstage does not test on your behalf. When the core framework changes how a registration or extension is wired, every internal plugin that exposes or consumes your extension points must change in step. Plugins that depend only on the public, documented APIs are cheaper to move. Document each extension point, its consumers and its owner, so the upgrade team knows which changes can cascade across the portal.
Why does a lack of automated tests make plugin upgrades slower?
Without automated tests, the only way to confirm a plugin still works after an upgrade is manual checking, which grows with every page, route and catalog view the plugin touches. Teams often find breakage late in staging or in front of users. Unit tests for backend routes, catalog processors and frontend components, plus a smoke test of the running app, let the upgrade team find failures on the first build. Ask whether each plugin has tests that run in CI and how long a full run takes. Plugins with no tests should be counted as higher effort in any quote.
How do community plugin dependencies change the upgrade effort?
Community plugins add effort because their maintainers release on their own schedule, and some have moved to the Backstage community-plugins repository with new package names. Your custom plugins may depend on a community package that has not yet supported the Backstage release you are targeting, which blocks the whole upgrade until a version is found or the dependency is replaced. Check each community dependency's release history, maintenance status and supported Backstage version before you plan. Keep a list of pinned versions so the team can see which upgrade is blocked by which package.
Does the number of Backstage releases skipped change the upgrade effort?
Yes. The more releases an app has skipped, the more deprecations, template changes and API moves it has to absorb in one pass. Staying on the monthly main line keeps each step small, and an app that has skipped many months may need several steps with testing between them. Count how many releases your app is behind using the Backstage releases page and the Upgrade Helper before you estimate. The gap is a one-time cost for the catch-up, but a steady monthly cadence keeps it recurring and small.
How does the number of teams that own plugins affect upgrade work?
Each owning team sets its own release timing, test coverage and review capacity, so the number of owners determines how much coordination the upgrade needs. When several teams own plugins that depend on each other, one team's delay holds up everyone else. A single platform team that owns all plugins can move faster but may become a bottleneck. Confirm who signs off each plugin, who merges fixes, and who answers for a failed upgrade before the work starts. Clear ownership is often the cheapest way to reduce upgrade time.
Who owns plugin compatibility after the upgrade
The platform team owns the Backstage app and the core version bumps, but plugin authors own whether their plugin still works after each bump. Splitting the work this way means the person who changes a plugin is the person who understands its code, its tests and its consumers. In practice, the app repository owner runs yarn backstage-cli versions:bump, applies the template changes from the Upgrade Helper to the app and backend packages, and then routes each failing custom plugin to a named maintainer. Each internal plugin should have a listed owner in its catalog entry, so a failing build does not stall in a shared channel. Before the upgrade starts, confirm who signs off the release as a whole. That sign-off person should be named in the change record, separate from the individual plugin owners, and should have authority to delay a release when a plugin is broken.
Set a compatibility review that happens on a fixed rhythm rather than only when something breaks. A monthly review fits the main release line, which ships monthly according to the Backstage versioning policy. At each review, the platform team lists every custom plugin, its owner, the Backstage version it was last tested against, and any deprecation warnings from the build. If your organization tracks the weekly next line, add a lighter check there for plugins that touch APIs still in flux. Record the outcome in a single table or document that the sign-off owner approves before the production upgrade. Ask each plugin owner to state whether their plugin imports any package that is deprecated or was removed, such as the older backend-common package, because those imports are the most common source of surprise breakage.
When a plugin fails, decide between patching it and retiring it before anyone starts coding. Patch when the plugin still serves a current business need and the required change is contained, such as moving to a new extension point or updating a test harness. Retire, or replace with a community or vendor plugin, when the plugin has no active owner, when the fix would rewrite most of its code, or when the same capability now exists in core or in a maintained package. Write the decision down with the owner, the cost of each option, and the date by which the plugin must be either fixed or removed. As an illustrative rule, a plugin with no maintainer willing to take the next upgrade should be scheduled for retirement at the next review, not carried forward through another release. Confirm the status of any package you depend on against the release notes before deciding, because the maintenance state of community plugins can change.
How much does it cost to keep custom Backstage plugins working?
What actually drives the cost of keeping custom Backstage plugins compatible?
The cost follows the number of plugins, how far they reach into core APIs, and how often your Backstage version moves. A plugin that only uses stable frontend components and the public plugin API is cheap to carry forward. A plugin that imports internal packages, depends on deprecated modules such as @backstage/backend-common, or extends backend behavior through older extension points needs more work on every bump. Other cost drivers are the size of your test coverage, how many environments must be verified, and whether your team has a named owner for each plugin. Ask the provider to break the quote down by plugin and by upgrade cycle so you can see which items recur.
How long does a custom Backstage plugin upgrade take?
Duration depends on the plugin's dependency surface and the distance between your current Backstage release and the target. A plugin that only needs version alignment and a passing test run is a short task. A plugin that must move off a deprecated package, adopt a new backend or frontend system pattern, or change its tests is a larger one. No duration is given here because no researched figure applies to your codebase. Ask for a per-plugin estimate in the written scope, with the Backstage versions it covers and the test evidence you will receive before sign-off.
What does the work need from our engineering team?
Your team needs to provide the plugin source, a working development environment, access to a non-production Backstage instance that matches production configuration, and a named reviewer who understands the business behavior the plugin supports. Your team also decides on acceptance criteria, such as which catalog entities, scaffolder actions or API calls must still work after the upgrade. Plan for a reviewer to be available during the test window, because a compatibility fix often changes behavior that only your domain experts can confirm.
Can our own team maintain custom Backstage plugins without an outside partner?
Yes, many organizations do this in house, and the Backstage project publishes the upgrade tooling your team would use. Whether it is practical depends on whether you have engineers who know TypeScript, the Backstage plugin model and your CI pipeline, and whether they have time for the monthly release cadence. The Backstage versioning policy describes a main release line shipped monthly and a next line shipped weekly, so the work recurs. Compare the cost of a dedicated owner with a retainer that covers routine bumps and leaves larger changes to a fixed-scope project.
Should we rebuild a custom plugin or patch it to work on the new version?
Patch when the plugin's logic is sound and the breaking changes are confined to imports, configuration or a small number of API calls. Rebuild when the plugin relies on internal behavior that no longer exists, when it duplicates a core feature that has since shipped, or when its tests cannot be trusted. As an illustrative example, a plugin that wraps a deprecated backend service may be cheaper to rewrite against the current plugin API than to patch line by line. Ask the provider for a short assessment of each plugin that recommends patch or rebuild with the reasons, before any build work is priced.
What should we ask for in a fixed-scope quote for plugin compatibility work?
Ask for a written scope that lists each plugin, the starting and target Backstage versions, the packages and extension points in use, and the changes expected. Request the acceptance tests, the environments where verification happens, and the handover format, including updated documentation and pinned dependency versions. Ask what is excluded, such as new features, search engine changes or plugins that moved to the community repository, and whether a follow-up window is included for issues found after release. Also ask how future bumps will be priced if the work recurs.
Does the work cover security fixes and vulnerability backports in our plugins?
Compatibility work and security work overlap but are not the same. The Backstage versioning policy says high and critical severity vulnerabilities will always be backported to releases from the last 6 months if feasible, and other security fixes may be backported. Your custom plugins still need their own dependency updates, code review and testing when those fixes arrive. Ask the provider whether security patch handling is part of the scope or a separate retainer item, and who approves a release that contains a security change.
How DeployOpen works on this
DeployOpen scopes, builds, tests and documents the compatibility work for your internal Backstage plugins as a written, fixed-scope engagement inside your own infrastructure. We hand over plugins your team can maintain through each upgrade, and we offer ongoing support as a retainer if you want us to keep carrying the work.
How we scope
- We inventory every internal plugin, its backend and frontend packages, and the core APIs it depends on.
- We list deprecated imports such as backend-common and mark which plugins use extension points or other APIs that have changed.
- We agree the upgrade target, deliverables and timeline in writing before work starts, as engagements are fixed-scope.
How we build
- We move each plugin to the current core APIs in a branch, applying template changes alongside the @backstage package bump.
- We add or update plugin tests so each release line is checked against your own plugin behavior, not only the core tests.
- We record each compatibility decision, including any plugin we recommend rewriting rather than patching.
How we hand over
- We document the upgrade steps, test commands and known breaking points so your engineers can repeat the process.
- We walk your platform team through the changes and confirm they can run the test suite and release a plugin on their own.
- We deliver the compatibility notes and runbook in your own repository, under your control.
How we support
- Ongoing support covers compatibility checks against upcoming Backstage releases, available as a retainer.
- Retainer scope, response expectations and the frequency of checks are set in writing, so you can confirm them before signing.
- Ask us to confirm how your current Backstage release and Node.js version affect the work before agreeing to a scope.

