v1.52.0
These are the release notes for the v1.52.0 release of Backstage.
A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done.
Highlights
BREAKING: Default discovery API changed to FrontendHostDiscovery
The default discovery API implementation in @backstage/plugin-app has been changed to FrontendHostDiscovery, which supports the discovery.endpoints configuration for per-plugin endpoint overrides. This means the frontend will now honor discovery.endpoints configuration, including string target values. If you currently use internal-only targets there, update them to the object form and move the internal URL to target.internal, omitting target.external (or setting it to a browser-reachable URL) to avoid routing the frontend to internal URLs.
BREAKING: Removed immediate mode stitching
The catalog.stitchingStrategy.mode: 'immediate' setting, which was deprecated in v1.51.0, has been removed. All stitching now uses the deferred mode, which processes entities asynchronously via a worker queue. If your configuration still includes catalog.stitchingStrategy.mode: 'immediate', it will be ignored with a deprecation warning. The pollingInterval and stitchTimeout settings continue to work as before.
BREAKING: Backstage UI updates
This release brings several notable additions and changes to Backstage UI:
Async collections: Both Combobox and Select now support async collections, incremental loading, client and server search, and rich or custom item rendering. Loading placeholders and stale result indicators are exposed via public CSS classes for theme customization. The Combobox and Select popovers now correctly load additional pages as users scroll, rather than loading every page immediately.
Semantic color tokens: A new set of semantic color token families has been introduced -- Accent, Announcement, Warning, Negative, and Positive -- each providing a consistent set of background, foreground, and border tokens for both light and dark themes. A gray scale and updated foreground tokens are also included. The previous tokens remain in place for backward compatibility but are now deprecated. A new @backstage/no-deprecated-bui-tokens ESLint rule warns when deprecated tokens are referenced in JavaScript or TypeScript files.
New components: A NumberField component has been added for numeric input with support for min, max, step, and keyboard increment/decrement. Contributed by @jabrks in #34264.
Breaking changes:
ComboboxPropsis now a union type. Replace interfaces that extendComboboxPropswith type intersections:- interface MyComboboxProps extends ComboboxProps {
- trackingId: string;
- }
+ type MyComboboxProps = ComboboxProps & {
+ trackingId: string;
+ };SelectPropsis now a union type and the popover list content is no longer a direct child of.bui-SelectPopover. Apply the same intersection migration asComboboxProps, and update CSS selectors that target list content as a direct child of.bui-SelectPopover.
Check the BUI Changelog for more details.
New experimental package: @backstage/connections
A new @backstage/connections package has been added as an experimental feature. Do not use this package unless you are experimenting with this new system. A Connection is a piece of configuration that stores an external host and the credentials required to authenticate with it. The goal of Connections to eventually replace the integrations concept, and to support a much wider range of systems. More information is available in BEP-0014.
Contributed by @neoreddog in #34546 and #34592
Catalog totalItems control and split count queries
The /entities/by-query endpoint now accepts a totalItems parameter ('include' or 'exclude', default 'include') that controls whether the response's totalItems count is computed. Pass 'exclude' to skip the count entirely when the caller does not need it -- useful for cursor-paginated UIs that only display the count cosmetically. The corresponding CatalogApi.queryEntities method in @backstage/catalog-client has been updated to accept the same option.
Internally, the entity list provider now fetches the entity list and the total count as two separate parallel requests. The list query skips the expensive count computation, so the table populates immediately while the count arrives asynchronously. A new totalItemsLoading field on EntityListContextProps lets consumers distinguish a stale count from a fresh one. The catalog table now keeps stale rows visible during filter changes and page navigation instead of replacing the entire table body with a spinner.
Catalog performance improvements
Several additional performance improvements have been made to the catalog backend:
- Split the
queryEntitieslist and count into separate queries instead of a multi-reference CTE. When the CTE was referenced twice, PostgreSQL refused to inline it, forcing full materialization before applyingLIMIT. The standalone count query also fixes a pre-existing bug wheretotalItemswas inflated for entities with multi-valued sort fields. - Added extended multi-column statistics on
(key, value)in thesearchtable (PostgreSQL only), fixing severe row count estimation errors on compound filter queries that caused 10-40x slower catalog list views. - Added a migration that tunes PostgreSQL automatic vacuum thresholds on key catalog tables and fixes column statistics for
entity_idin thesearchtable. - Dropped the legacy
search_entity_id_idxindex which is now redundant and was causing the query planner to choose an inefficient scan pattern for catalog list queries with multiple sort fields. - Optimized
entitiesBatchon PostgreSQL to use= ANY(array)instead ofWHERE IN ($1, $2, ...), producing a single stable query plan regardless of batch size. - Fixed a race condition in the stitch queue where row locks were released before the subsequent timestamp bump, allowing multiple workers to claim the same rows.
- Improved stitch queue semantics to prevent overlapping stitches for the same entity.
Actions secrets schema support
Actions can now declare a Zod secrets schema separate from the input schema in @backstage/backend-plugin-api, enabling surfaces to collect sensitive credentials independently from tool arguments. A new v2 invoke endpoint (/.backstage/actions/v2/actions/:id/invoke) accepts a wrapped body format with secrets validation, while the existing v1 endpoint remains unchanged. The mock actions registry in @backstage/backend-test-utils has been updated to support validating and forwarding secrets.
Scaffolder field extension template
A new scaffolder-field-extension-module template has been added to backstage-cli new, making it easier to scaffold custom Scaffolder form field extensions.
Entity list provider refresh function
The useEntityList hook from @backstage/plugin-catalog-react now exposes a refresh function, allowing consumers to programmatically trigger a refresh of the entity list data.
Contributed by @mtlewis in #34555
Catalog export button
A new CatalogExportButton component has been added to @backstage/plugin-catalog, providing CSV and JSON export support for the CatalogIndexPage.
Contributed by @the-serious-programmer in #31837
Lazy-loaded core components
The react-syntax-highlighter and @dagrejs/dagre dependencies are now lazy-loaded in @backstage/core-components, so they are no longer pulled in eagerly through the barrel export. This reduces the upfront module cost of importing from @backstage/core-components by roughly 10 MB.
Additional fixes and improvements
- Fixed redundant API calls during entity list initialization. Filter components that register their initial state in quick succession no longer trigger multiple identical fetches, and frontend-only filter changes are applied synchronously without a network round-trip.
- Fixed the Microsoft Graph provider's
userGroupMemberpath by reverting the server-sideaccountEnabled eq truebase filter that broke the group members endpoint. Disabled users are now filtered client-side in both paths. - Fixed a bug where setting
user.selectto an empty array in the Microsoft Graph provider would cause all users to be dropped from the catalog. Contributed by @mtlewis in #34505. - Fixed resolution of relative
$refpaths in OpenAPI and AsyncAPI specs for cross-directory refs and nested refs at depth > 1. Contributed by @aramissennyeydd in #33954. - Fixed dynamic backend plugin loading to fall back to the main package export when an alpha
package.jsonis present but does not provide a plugin entrypoint. Contributed by @gashcrumb in #34535. - Fixed the proxy-based sign-in page failing to read session tokens encoded with the URL-safe base64 alphabet. Contributed by @officialasishkumar in #34354.
- Fixed the built-in rate limiter throwing a validation error when
backend.rateLimitis enabled. IPv6 clients are now grouped by address block rather than individual address. Contributed by @officialasishkumar in #34353. - Fixed the task worker retry loop to respect the abort signal, allowing workers to shut down gracefully instead of retrying indefinitely.
- Fixed autologout not working correctly when closing all tabs. Contributed by @jescalada in #31466.
- Fixed text clipping in
SidebarSubmenuItemby correcting line-height. Contributed by @GitanshKapoor in #34438. - Fixed the
Tablecomponent not filling its container width in Firefox. Contributed by @robingileborg in #34539. - Restored user-supplied task secrets in scaffolder dry-run executions; only environment secrets remain stripped. Contributed by @Naga15 in #34481.
- Added retry with exponential backoff to
Git.push()for scaffolder actions that encounter transient failures when the repository is not yet fully provisioned. Contributed by @pc-bob in #34295. - Added a fallback for
publish:githubandgithub:repo:pushthat retries via the GitHub GraphQL API when the git push fails with a connection-level error, working around network proxies that block binary pack data. Contributed by @polasudo in #34036. - Added a Bitbucket Server SCM event translation layer to enable instant catalog reprocessing when repositories are pushed to or renamed. Contributed by @alien2003 in #34407.
- Added optional
getOptionLabelandrenderOptionprops toEntityAutocompletePicker. Contributed by @rferreira98 in #33823. - Added full text searching of Location target URLs in catalog tables.
- Added a
forwardedPreferredUsernameMatchingUserEntityNamesign-in resolver to the OAuth2 proxy provider. Contributed by @JessicaJHee in #34156. - Added a
RepoOwnerPickercustom variant for GitLab in the scaffolder. Contributed by @asheen1234 in #33690. - Added a
disablePublicEntryPointconfig option to the app backend to opt out of the automatic public sign-in entry point. - Added a default export to the
@backstage/plugin-techdocs-module-addons-contrib/alphaentrypoint for dynamic plugin loaders. Contributed by @jroebu14 in #34514. - Added missing i18n support for TechDocs plugin components. Contributed by @its-mitesh-kumar in #31731.
- Increased the events bus request body limit to 5 MB to allow larger event payloads. Contributed by @stephenglass in #34464.
- MCP actions backend now validates each action against the MCP tool schema and skips invalid ones instead of failing the entire response. Contributed by @hudsonb in #34046.
- Migrated the notifications backend internal router to be generated from the plugin's OpenAPI specification. Contributed by @aramissennyeydd in #34179.
- Removed the default Kubernetes standalone page that was registered at
/kubernetesby mistake. Contributed by @vinzscam in #34522. - HTTPS agents are now pooled per cluster in the Kubernetes fetcher. Contributed by @alde in #34401.
HAS_LABELandHAS_ANNOTATIONpermission rules are now case insensitive. Contributed by @04kash in #34572.- Altered the
ingestions.last_errorcolumn type in the incremental ingestion module to remove the 255-character restriction. Contributed by @koalaty-code in #34347. - Fixed the
toastApinot being provided for the old frontend system. Contributed by @apc-kamezaki in #34112. - Fixed header tab links to respect the configured router
basename. Contributed by @Naycon in #34469. - Fixed the GitLab URL reader issue with retrieving the repository archive tree. Contributed by @stijnbrouwers in #34415.
- Changed visibility of Bitbucket username configuration as it is not a secret. Contributed by @robingileborg in #34398.
- Newly scaffolded apps now use Yarn 4.13.0 and enable Yarn's
npmMinimalAgeGate: 3dsetting as a defense against supply-chain attacks. Contributed by @aramissennyeydd in #33701. - Made Toast text content selectable. Contributed by @clairep94 in #34531.
- Upgraded
infinispanfrom^0.12.0to^0.13.0to address known vulnerabilities. - Removed unused
json-schemaruntime dependency across several packages. Contributed by @rohanjethwani17 in #34143. - Added a
mountPathoption torenderInTestAppin@backstage/frontend-test-utilsfor testing page components that depend on URL parameters. - Added
runClifor creating executable CLI packages from a fixed collection of directly imported CLI modules.
Security Fixes
This release does not contain any security fixes.
Contributors
Big shoutout to all 30 of you amazing folks who chipped in on this release: @04kash, @GitanshKapoor, @JessicaJHee, @Naga15, @Naycon, @alien2003, @apc-kamezaki, @aramissennyeydd, @asheen1234, @cdedreuille, @clairep94, @gashcrumb, @hudsonb, @its-mitesh-kumar, @jabrks, @jescalada, @jroebu14, @koalaty-code, @mtlewis, @neoreddog, @officialasishkumar, @pc-bob, @polasudo, @rferreira98, @robingileborg, @rohanjethwani17, @stephenglass, @stijnbrouwers, @the-serious-programmer, @vinzscam
Upgrade path
We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for keeping Backstage updated.
Links and References
Below you can find a list of links and references to help you learn about and start using this new release.
- Backstage official website, documentation, and getting started guide
- GitHub repository
- Backstage's versioning and support policy
- Community Discord for discussions and support
- Changelog
- Backstage Demos, Blog, Roadmap and Plugins
Sign up for our newsletter if you want to be informed about what is happening in the world of Backstage.