v1.51.0
These are the release notes for the v1.51.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: Removed deprecated NavItemBlueprint
The deprecated NavItemBlueprint has been removed from @backstage/frontend-plugin-api. Navigation items are now discovered from PageBlueprint extensions based on their title and icon params. If you were still using NavItemBlueprint, migrate by setting title and icon on the page extension instead. All built-in plugins have been updated accordingly.
Additionally, renderInTestApp from @backstage/frontend-test-utils no longer renders a sidebar or legacy nav-item extensions. The app nav extension is now disabled in the minimal test app shell.
BREAKING: Removed deprecated PortableSchema.schema property form
The deprecated property form of PortableSchema.schema has been removed from @backstage/frontend-plugin-api. The schema member is now a plain method that must be called as schema() — direct property access like schema.type or schema.properties is no longer supported.
BREAKING: Hardened OIDC default patterns
The default allowed patterns for CIMD and DCR in @backstage/plugin-auth-backend have been hardened. The previous permissive ['*'] wildcards have been replaced with specific defaults for known MCP clients. If you previously relied on the permissive defaults and have custom MCP clients, you will need to explicitly add their patterns to the allow list.
BREAKING: Cleaned up PolicyQueryUser type
The token and expiresInSeconds fields have been removed from PolicyQueryUser in @backstage/plugin-permission-node. These were previously deprecated in favor of credentials with coreServices.auth. The identity field has been deprecated. A new CachedUserInfoService with a 5-second TTL cache and in-flight request coalescing has been added to reduce repeated user info lookups.
BREAKING: Catalog entity pagination excludes entities without sort field
When paginating entities with an order field via /entities/by-query, entities that lack the order field are now excluded from both the result set and the totalItems count. Previously these entities appeared at the end via NULLS LAST, but cursor-based pagination could not actually reach them past the first page — the count over-reported the number of navigable entities.
BREAKING: Microsoft Graph disabled users filtered by default
The @backstage/plugin-catalog-backend-module-msgraph and @backstage/plugin-catalog-backend-module-msgraph-incremental providers now filter out disabled user accounts by default. The provider automatically applies an accountEnabled eq true filter, combining it with any custom user.filter you provide. If you need to ingest disabled accounts, set the filter to explicitly include them.
Contributed by @mtlewis in #34165
BREAKING: Backstage UI updates
There are several new additions in Backstage UI:
New components: A Combobox component pairs a text input with a filterable dropdown, supporting sectioned options, icons, sizes, and custom typed values. New DatePicker and DateRangePicker components provide accessible date selection with calendar popovers built on React Aria. Flex item props (grow, shrink, basis) have been added to Box, Card, Grid, and Flex.
Header improvements: A sticky prop has been added to the Header component that keeps the title-and-actions bar fixed at the top of its scroll container. New description, tags, and metadata props provide richer header content. The breadcrumbs prop has been deprecated.
Other additions: Grouped options in Select, isPending prop replacing loading across components, searchDebounceMs and filterDebounceMs options for useTable, PasswordField visual alignment with TextField, a public --bui-bg-inherit CSS variable, and keyboard focus indicators on Card links.
Breaking changes:
- Header: Removed the main header class from the
Headercomponent. Custom styles targeting this class should be updated. @remixicon/reactdependency limited to versions below 4.9.0 due to a license change.- React Aria dependencies updated to v1.17.0 and migrated to monopackages.
The Combobox was contributed by @jabrks in #34118. The DatePicker was contributed by @Swiftwork in #34184. Flex item props were contributed by @mtlewis in #33948.
Check the BUI Changelog for more details.
AiResource catalog entity kind
A new AiResource catalog entity kind has been introduced, with entity types, validators, type guards, and model layer definitions exported from @backstage/catalog-model/alpha. Install @backstage/plugin-catalog-backend-module-ai-model to enable it. A new spec.type: 'mcp-server' structured subtype has also been added to the API kind, with a spec.remotes list for representing MCP server connections.
New plugin: Microsoft Graph incremental ingestion
A new @backstage/plugin-catalog-backend-module-msgraph-incremental module provides cursor-based incremental ingestion for Microsoft Graph. Unlike MicrosoftGraphOrgEntityProvider, this module never holds the full dataset in memory — each burst processes a single page of up to 999 users or 100 groups. The cursor is persisted so a pod restart resumes from the last completed page.
Contributed by @sriharsha9618 in #34053
Scaffolder form decorators promoted to stable
The formDecorators field on template specs, the formDecoratorsApiRef API, and the FormDecoratorBlueprint have been promoted from @alpha to @public across @backstage/plugin-scaffolder, @backstage/plugin-scaffolder-react, @backstage/plugin-scaffolder-common, and @backstage/plugin-scaffolder-backend. The previous EXPERIMENTAL_formDecorators field continues to work as a deprecated alias. Decorator input is now validated against the configured zod schema before execution.
Experimental BUI scaffolder form theme
An experimental Backstage UI form theme has been added for scaffolder forms. All default field extensions render BUI variants when enabled. Set enableBackstageUi: true in the sub-page:scaffolder/templates extension config to try it out.
Template groups configuration
The sub-page:scaffolder/templates extension now accepts a groups config field for defining template groups on the template list page. Each group has a title and a filter predicate. Templates not matched by any group fall into an "Other Templates" group.
app:
extensions:
- sub-page:scaffolder/templates:
config:
groups:
- title: Recommended Services
filter:
spec.type: service
- title: Documentation
filter:
spec.type: documentation
The TemplateCard is now a swappable component — apps using the new frontend system can replace it via SwappableComponentBlueprint.
ExtensionPointFactoryMiddleware for backend
A new ExtensionPointFactoryMiddleware type and createExtensionPointFactoryMiddleware helper have been added to @backstage/backend-app-api, allowing extension point outputs to be replaced at backend creation time. The defaultServiceFactories export has been added to @backstage/backend-defaults for use with createSpecializedBackend.
Contributed by @UsainBloot in #33782
Alpha TracingService
An alpha TracingService has been added to @backstage/backend-plugin-api and @backstage/backend-defaults, providing a unified interface for emitting trace spans across Backstage plugins. The service includes context and propagation support for bridging OpenTelemetry context across async boundaries. MCP tools/call invocations now emit trace spans following OpenTelemetry server-side MCP semantic conventions. A corresponding mock is available in @backstage/backend-test-utils.
Contributed by @iamEAP in #34087
Catalog performance improvements
Several performance improvements have been made to the catalog backend:
- The entity listing endpoint now lets PostgreSQL walk the
(key, value, entity_id)index in sorted order and short-circuit onLIMIT, reducing typical paginated list times from seconds to milliseconds. - The entity facets endpoint uses an inner join rather than
WHERE entity_id IN (subquery)when filters are applied, with measured improvements from ~1.2x to 7x. - The facets aggregation simplified from
COUNT(DISTINCT entity_id)toCOUNT(*), enabled by the new unique constraint. - The
catalog_entities_countmetric now shares a single cached query between Prometheus and OpenTelemetry gauges. - A missing index on
relations.target_entity_refhas been added, fixing full sequential scans on orphan deletion, entity ancestry, and eager pruning queries. - Incremental ingestion
WHERE ref IN (...)queries now use= ANY($1)with a single array parameter to reduce prepared statement bloat. - A new migration removes duplicate rows from the
searchtable, creates covering indices, and adds aUNIQUEconstraint on(entity_id, key, value). For large installations, it is recommended to run the provided SQL commands before deploying — see the changelog for details.
New ESLint no-self-package-imports rule
A new no-self-package-imports lint rule has been added to @backstage/eslint-plugin, enabled as error in the recommended config. It reports when a package imports itself by its own name instead of using a relative path — a pattern that causes circular initialization errors in bundled ESM and with jest.requireActual.
Contributed by @dyatko in #34041
AWS web identity token file support
Added webIdentityTokenFile to @backstage/integration-aws-node account configuration. When set along with a roleName, DefaultAwsCredentialsManager retrieves credentials by calling AssumeRoleWithWebIdentity using the file's contents as the web identity token. The file is re-read on each credential refresh.
Contributed by @hudsonb in #34149
TechDocs: disable external font downloads
Added support for disabling external font downloads in TechDocs, useful for air-gapped Backstage instances. Available via the techdocs.generator.mkdocs.disableExternalFonts app-config option and the techdocs-cli generate --disableExternalFonts CLI flag.
Contributed by @karthikjeeyar in #31838
always() and failure() status functions for scaffolder steps
Added always() and failure() status check functions for scaffolder steps. These can be used in the if field to control execution after failures. always() ensures a step runs regardless of previous step outcomes, while failure() runs a step only when a previous step has failed.
Contributed by @Ferin79 in #32890
Deprecated immediate mode stitching
The catalog.stitchingStrategy.mode: 'immediate' setting has been deprecated. A warning is now logged on startup when immediate mode is configured. Immediate mode will be removed in the next Backstage release.
Additional fixes and improvements
- Fixed scheduler
sleepfiring immediately for durations longer than ~24.8 days, caused by Node.jssetTimeoutoverflowing its 32-bit millisecond limit. - Fixed an issue where navigating to an unknown sub-path on an entity page would silently render the first available route instead of showing a not-found page.
- Fixed widgets not being movable or resizable after saved edits on the home page. Contributed by @aurnik in #33721.
- Fixed a regression that caused disabled nav items to appear in the navigation bar. Contributed by @benjidotsh in #33788.
- Fixed Valkey cluster mode to use the correct
Clusterclass instead ofcreateClusterfrom@keyv/redis. Contributed by @ganievs in #33895. - Fixed a race condition in
CachedUserInfoServicewhere a failed request could incorrectly evict a newer cache entry. - Fixed
mockCredentialsto include the internalversion: 'v1'field on all credential objects. - Fixed filter predicates that mix operator keys (
$all,$any,$not) with other keys now being rejected instead of silently dropping conditions. - Fixed a bug in
PackageGraph.listChangedPackageswhere removed dependencies were not detected during lockfile analysis. - Fixed several database migration
downfunctions in the catalog backend that were not properly reversible. - Fixed a bug causing
--legacyCopyReadmeMdToIndexMdoption to fail if docs directory is not present. Contributed by @rtar in #33370. - Pinned the Jest version range in app templates to
~30.2.0to prevent automatic upgrades to Jest 30.4.x, which requires Node.js v24.9+. - Invalid feature flag declarations no longer crash the app during bootstrap — they are now reported through the error collector and skipped.
- Improved the OAuth consent dialog for MCP authorization by showing more client details. Contributed by @djamaile in #34130.
- Improved OIDC error messages to include the rejected redirect URI or client ID.
- Refresh token usage now verifies that the user's catalog entity still exists before issuing a new access token. Contributed by @mtlewis in #34142.
- Limit the size of fetched client ID metadata documents to prevent oversized responses.
- The notification description in the notifications table is now a swappable component.
- Added scope-based Slack message update support for the notifications backend. Contributed by @erikmiller-gusto in #33649.
- Added a search backend action for querying the search engine via the actions registry. Contributed by @drodil in #31010.
- Added MCP
tools/calltrace spans following OpenTelemetry semantic conventions. Contributed by @iamEAP in #34089. - Scheduled Tasks page in DevTools now refreshes automatically after a task is triggered or cancelled. Contributed by @officialasishkumar in #34049.
- Migrated
ConfigContentcomponent in DevTools from Material UI to Backstage UI. Contributed by @AdityaK60 in #33252. - Scaffolder list-tasks action now supports a
statusfilter parameter. Contributed by @johnmcollier in #33122. - Added
allowEmptyinput option to thegitlab:repo:pushscaffolder action. Contributed by @elaine-mattos in #33602. - Improved Octokit client creation in the GitHub scaffolder module to support retries. Contributed by @adobejmong in #34027.
- Added optional
clustersCacheTtlMsoption toKubernetesBackendClientfor caching cluster responses. Contributed by @alde in #34136. - Prioritized i18n translations over
theme.titlefor theme names in user settings. Contributed by @its-mitesh-kumar in #34113. - Added experimental support for checking suspended GitHub users via REST API. Contributed by @mtlewis in #34300.
- The
GithubMultiOrgEntityProvidernow emits entities in a stable order during full mutations. - Added permission authorization checks to the unprocessed entities read endpoints.
- Upgraded Module Federation packages to v2.3.3 to address known vulnerabilities. Contributed by @secustor in #33949.
- Removed the
uuiddependency across many packages, replacing it with the built-incrypto.randomUUID().
Security Fixes
This release does not contain any security fixes.
Contributors
Big shoutout to all 34 of you amazing folks who chipped in on this release: @AdityaK60, @Ferin79, @Naycon, @Swiftwork, @UsainBloot, @adobejmong, @alde, @aurnik, @benjidotsh, @cdedreuille, @copilot-swe-agent, @davidjosefson-neo4j, @deepthi-28, @djamaile, @drodil, @dyatko, @elaine-mattos, @emmaindal, @erikmiller-gusto, @etienne-napoleone, @ganievs, @hudsonb, @iamEAP, @its-mitesh-kumar, @jabrks, @johnmcollier, @jtbry, @karthikjeeyar, @mtlewis, @officialasishkumar, @rtar, @secustor, @sriharsha9618, @wss-dogara
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.