Skip to main content
Version: Next

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:

  • ComboboxProps is now a union type. Replace interfaces that extend ComboboxProps with type intersections:
    - interface MyComboboxProps extends ComboboxProps {
    - trackingId: string;
    - }
    + type MyComboboxProps = ComboboxProps & {
    + trackingId: string;
    + };
  • SelectProps is now a union type and the popover list content is no longer a direct child of .bui-SelectPopover. Apply the same intersection migration as ComboboxProps, 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 queryEntities list 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 applying LIMIT. The standalone count query also fixes a pre-existing bug where totalItems was inflated for entities with multi-valued sort fields.
  • Added extended multi-column statistics on (key, value) in the search table (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_id in the search table.
  • Dropped the legacy search_entity_id_idx index 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 entitiesBatch on PostgreSQL to use = ANY(array) instead of WHERE 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 userGroupMember path by reverting the server-side accountEnabled eq true base filter that broke the group members endpoint. Disabled users are now filtered client-side in both paths.
  • Fixed a bug where setting user.select to 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 $ref paths 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.json is 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.rateLimit is 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 SidebarSubmenuItem by correcting line-height. Contributed by @GitanshKapoor in #34438.
  • Fixed the Table component 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:github and github:repo:push that 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 getOptionLabel and renderOption props to EntityAutocompletePicker. Contributed by @rferreira98 in #33823.
  • Added full text searching of Location target URLs in catalog tables.
  • Added a forwardedPreferredUsernameMatchingUserEntityName sign-in resolver to the OAuth2 proxy provider. Contributed by @JessicaJHee in #34156.
  • Added a RepoOwnerPicker custom variant for GitLab in the scaffolder. Contributed by @asheen1234 in #33690.
  • Added a disablePublicEntryPoint config 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 /alpha entrypoint 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 /kubernetes by mistake. Contributed by @vinzscam in #34522.
  • HTTPS agents are now pooled per cluster in the Kubernetes fetcher. Contributed by @alde in #34401.
  • HAS_LABEL and HAS_ANNOTATION permission rules are now case insensitive. Contributed by @04kash in #34572.
  • Altered the ingestions.last_error column type in the incremental ingestion module to remove the 255-character restriction. Contributed by @koalaty-code in #34347.
  • Fixed the toastApi not 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: 3d setting as a defense against supply-chain attacks. Contributed by @aramissennyeydd in #33701.
  • Made Toast text content selectable. Contributed by @clairep94 in #34531.
  • Upgraded infinispan from ^0.12.0 to ^0.13.0 to address known vulnerabilities.
  • Removed unused json-schema runtime dependency across several packages. Contributed by @rohanjethwani17 in #34143.
  • Added a mountPath option to renderInTestApp in @backstage/frontend-test-utils for testing page components that depend on URL parameters.
  • Added runCli for 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.

Below you can find a list of links and references to help you learn about and start using this new release.

Sign up for our newsletter if you want to be informed about what is happening in the world of Backstage.