v1.50.0
These are the release notes for the v1.50.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: Identity token ownership claim removed by default
The auth.omitIdentityTokenOwnershipClaim setting now defaults to true. Backstage user tokens issued by the auth backend will no longer contain the ent claim with the user's ownership entity refs. This means tokens in large organizations no longer risk hitting HTTP header size limits.
To get ownership info for the current user, code should use the userInfo core service. The setting can still be set back to false if needed, but it will be removed entirely in a future release.
BREAKING: Standard Schema replaces createSchemaFromZod
The deprecated createSchemaFromZod helper has been removed from @backstage/frontend-plugin-api. A new configSchema option for createExtension and createExtensionBlueprint accepts direct schema values from any Standard Schema compatible library with JSON Schema support, such as zod v4 or the zod/v4 subpath from zod v3. Note that direct zod v3 schemas are not supported by the new option — use import { z } from 'zod/v4' from the zod v3 package, or upgrade to zod v4.
See the 1.50 migration documentation for more information.
BREAKING: Backstage UI updates
There are several new additions in Backstage UI, including a new Badge component for non-interactive labeling, a RangeSlider for numeric range selection, a CheckboxGroup component, and a showPaginationLabel prop for controlling pagination label visibility in tables. The TableBodySkeleton has been exported for use outside the built-in Table, and SearchAutocomplete now adapts its background based on its parent container. The useTable complete mode now supports disabling pagination via paginationOptions: { type: 'none' }. Tabs now respect prefers-reduced-motion for indicator animations, and form field descriptions are now properly connected to inputs via aria-describedby for screen reader accessibility.
The RangeSlider component was contributed by @AmbrishRamachandiran in #33112.
There are also several breaking changes to note:
- Header tabs: The
tabsprop now usesHeaderNavTabItem[]instead ofHeaderTab[]. Tabs render as a<nav>element with links instead ofrole="tablist". A newactiveTabIdprop controls which tab is highlighted, with automatic route-based detection when omitted. - Header tab
hrefresolution: Tabhrefvalues are now resolved through the router context instead of being passed raw. Relativehrefvalues are resolved against the current route, and absolute values may be affected by the router'sbasenameconfiguration. - PluginHeader: Removed the
toolbarWrapperelement. Update custom CSS targeting.bui-PluginHeaderToolbarWrapperto use.bui-PluginHeaderToolbarinstead. - React 17 dropped: The minimum supported React version is now 18.
Check the BUI Changelog for more details.
BREAKING: Removed deprecated PermissionedRoute
The deprecated PermissionedRoute component has been removed from @backstage/plugin-permission-react. Use RequirePermission instead.
BREAKING: Removed deprecated signal service exports
The deprecated SignalService and DefaultSignalService exports have been removed from @backstage/plugin-signals-node. Use SignalsService and DefaultSignalsService instead.
BREAKING ALPHA: Catalog node deprecated alpha exports removed
Several deprecated exports have been removed from @backstage/plugin-catalog-node/alpha:
catalogServiceRef— use the stable export from@backstage/plugin-catalog-nodeCatalogLocationsExtensionPoint/catalogLocationsExtensionPoint— use the non-alpha equivalentsCatalogProcessingExtensionPoint/catalogProcessingExtensionPoint— use the non-alpha equivalentsCatalogAnalysisExtensionPoint/catalogAnalysisExtensionPoint— use the non-alpha equivalentsCatalogPermissionRuleInput/CatalogPermissionExtensionPoint/catalogPermissionExtensionPoint— usecoreServices.permissionsRegistrydirectly
BREAKING PRODUCERS: Location entity refs and update method
The Location type in @backstage/catalog-client now includes a required entityRef field with the stable entity reference for each registered location. Any code that produces Location objects must now include this field. Location responses from the catalog backend include this new field, and it is filterable via POST /locations/by-query.
A new updateLocation method has been added to both CatalogApi and CatalogService for updating the type and target of an existing location. A corresponding PUT /locations/:id endpoint is now available in the catalog backend. Any code that implements CatalogService must provide this method.
Catalog model layer system (alpha, opt-in)
A new catalog model layer system has been added that allows plugins to declare and extend catalog entity kinds, annotations, labels, tags, and relations using JSON Schema. The new createCatalogModelLayer API in @backstage/catalog-model provides a builder for composing model definitions, and a compileCatalogModel function validates and merges them into a unified model. Built-in entity kinds now include model layer definitions.
On the backend, a new ModelProcessor in the catalog backend validates entities against compiled model schemas, and provideStaticCatalogModel in @backstage/plugin-catalog-node helps provide static models at startup. The @backstage/plugin-scaffolder-common package includes an example scaffolderCatalogModelLayer that declares the Template entity kind.
All of the above is in alpha, and you have to opt into it by actually providing model sources to the model extension point. If you do not - everything continues working the way it always has.
Experimental embedded Postgres for development
Added experimental support for using embedded-postgres as the database for local development. Set backend.database.client to embedded-postgres in your app config to enable this. The embedded-postgres package must be installed as an explicit dependency in your project.
New DialogApi.open() method
A new open method has been added to DialogApi that renders dialogs without any built-in dialog chrome, giving the caller full control over the dialog presentation. This avoids focus trap conflicts that occur when mixing components from different design libraries. The existing show and showModal methods are now deprecated in favor of open.
Plugin pages migrated to Backstage UI
Several plugin pages have been migrated to use Backstage UI components:
- TechDocs: The index and reader pages now use BUI
HeaderandContainer, with the plugin title changed to "Documentation". - Notifications: The notifications plugin has been migrated to use Backstage UI. Contributed by @drodil in #33699.
- Scaffolder actions page: Redesigned with a BUI sidebar list layout, built-in search filtering, and URL-based deep-linking to specific actions.
- InspectEntityDialog: Migrated from Material UI to Backstage UI components.
Notifications action
Added a new action to get a user's notifications through the actions registry.
Contributed by @drodil in #33831.
App route redirect configuration
The app/routes extension now supports configuring URL redirects through app-config. Redirects are specified as an array of {from, to} path pairs:
app:
extensions:
- app/routes:
config:
redirects:
- from: /old-path
to: /new-path
toError utility function
A new toError utility function is available in @backstage/errors for converting unknown values to ErrorLike objects. If the value is already error-like it is returned as-is, strings are used directly as the error message, and all other values are wrapped. Non-error causes passed to CustomErrorBase are now converted using toError rather than discarded.
FetchMiddlewares.clarifyFailures()
A new FetchMiddlewares.clarifyFailures() middleware has been added to @backstage/core-app-api that replaces the uninformative "TypeError: Failed to fetch" error with a message that includes the request method and URL. This middleware is now included in the default fetch API middleware stack in @backstage/app-defaults.
Auth0 federated logout and session caching
Sign-out now redirects the browser to Auth0's /v2/logout endpoint, clearing the Auth0 session cookie so that the next sign-in creates a new Auth0 session. Previously, only the Backstage session was cleared. Set federatedLogout: true in the Auth0 provider config to additionally clear the upstream IdP session (e.g. Okta, Google).
A new createAuth0Authenticator factory function uses a CacheService to cache Auth0 profile API responses for 1 minute during token refreshes, avoiding rate limits on repeated page refreshes.
Contributed by @UsainBloot in #33718.
Actions registry typed examples
Actions registered via the actions registry now support typed examples with compile-time-checked input and output values that match their schema definitions. A new execute-template action has been added for executing scaffolder templates through the actions registry.
Deprecated bootstrapEnvProxyAgents()
bootstrapEnvProxyAgents() in @backstage/cli-common has been deprecated in favor of Node.js built-in proxy support. Set NODE_USE_ENV_PROXY=1 alongside your HTTP_PROXY/HTTPS_PROXY environment variables instead. See the corporate proxy guide for details.
SCM event translation layers
New SCM event translation layers have been added for Azure DevOps, GitLab, and Bitbucket Cloud. These modules subscribe to their respective webhook events and translate them into generic catalog SCM events via the experimental catalogScmEventsServiceRef, enabling instant catalog reprocessing when repositories are pushed to, renamed, transferred, or deleted.
Contributed by @lokeshkaki in #33361, #33362, and #33410.
AWS RDS IAM authentication
Added support for AWS RDS IAM authentication for PostgreSQL connections. Set connection.type: rds along with host, user, and region in your database configuration to use short-lived IAM tokens instead of a static password. Requires the @aws-sdk/rds-signer package and an IAM role with rds-db:connect permission.
Contributed by @rolandfuszenecker-seon in #33680.
Catalog performance improvements
Several performance improvements have been made to the catalog backend:
- Entity filter queries now use
EXISTS (correlated subquery)patterns instead ofIN (subquery), enabling PostgreSQL semi-join optimizations and fixingNOT INNULL-semantics pitfalls. - Search table writes during stitching now sync only changed rows instead of doing a full delete and re-insert, reducing write churn.
- A deadlock in the catalog processing loop that occurred with multiple replicas has been fixed. The
getProcessableEntitiesmethod now correctly wrapsSELECT ... FOR UPDATE SKIP LOCKEDin a transaction.
The deadlock fix was contributed by @walsm232 in #33481.
TypeScript 6 and 7 compatibility
Several changes have been made to improve TypeScript 6 and 7 compatibility. DOM.AsyncIterable has been added to the default lib in the shared TypeScript configuration, enabling standard async iteration support for DOM APIs. The FlattenedMessages type in createTranslationRef has been fixed to avoid excessive type instantiation depth in newer TypeScript versions. The ESLint plugin has been updated to match stricter type checking in TypeScript 6 and up.
Deprecated humanizeEntityRef in favor of Catalog Presentation API
The humanizeEntityRef and humanizeEntity functions have been deprecated in favor of the Catalog Presentation API across multiple plugins. Use useEntityPresentation, EntityDisplayName, or entityPresentationApiRef instead.
The API docs and catalog graph plugins have also been updated to use the Catalog Presentation API for entity display.
Contributed by @AarishMansur in #33838 and @mvanhorn in #33386.
Conditional scaffolder output
Templates can now conditionally include output links and text items using an if property. Items where the if condition evaluates to false are excluded from the task output.
Contributed by @gusevda90 in #33332.
GitHub provider improvements
Fixed a bug where GithubEntityProvider with validateLocationsExist: true and filters.branch configured would always check for the catalog file on the repository's default branch instead of the configured branch.
Contributed by @thomvaill in #33601.
Added automatic retry on temporary errors (like 5XX) to the shared GitHub GraphQL client used by GithubOrgEntityProvider and GithubEntityProvider, improving resilience against intermittent GitHub API failures.
Contributed by @wpessers in #33632.
Scaffolder permission migration
The scaffolder backend now registers permissions through the PermissionsRegistryService instead of the deprecated createPermissionIntegrationRouter, fixing an issue where scaffolder permissions were not visible to RBAC plugins.
Additional fixes and improvements
- Fixed GitLab project topic filtering by using the correct API parameter. Contributed by @AmateurMind in #33111.
- Fixed the
SearchModalleaving the page in a broken state when closing. Contributed by @fcamgz in #31406. - Fixed
AwsS3UrlReaderfailing to read files from S3 buckets configured with custom endpoint hosts. Contributed by @wtravO in #33612. - Fixed the MCP OAuth 2.0 Protected Resource Metadata endpoint returning an internal plugin URL. Contributed by @koalaty-code in #33773.
- Fixed
.well-known/oauth-protected-resourceresource URL to comply with RFC 9728 Section 7.3. Contributed by @vincentrit in #33855. - Fixed a bug in large document indexing logic by using sub-transaction rollbacks. Contributed by @stanislav-c in #31494.
- Fixed occasional duplication of v5 class name prefix for MUI 5 components. Contributed by @StateFarmIns in #33054.
- Fixed CIMD redirect URI matching to allow any port for localhost addresses per RFC 8252. Contributed by @Sarabadu in #33446.
- The
MembersListCardnow prefersmetadata.titleovermetadata.namewhen displaying the group membership card. Contributed by @Parsifal-M in #33885. - Fixed
SingleInstanceGithubCredentialsProviderto return app credentials whengetCredentialsis called with a bare host URL. - Added
Kindfield to theAboutCard. Tags moved before Type and Lifecycle, Kind placed after them. - The unprocessed entities view is now primarily intended for use as a tab within the DevTools plugin.
HostDiscoverynow logs a warning whenbackend.baseUrlis set to a localhost address whileNODE_ENVisproduction.
Security Fixes
This release does not contain any security fixes.
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.