docs/releases/v1.50.0.md
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.
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.
The new frontend system now uses Standard Schema for extension configuration. A new configSchema option has been added to createExtension, createExtensionBlueprint, as well as the override and makeWithOverrides methods on extension definitions and blueprints. This option accepts direct schema values from any Standard Schema compatible library with JSON Schema support, replacing the old config.schema callback format which is now deprecated.
To use the new configSchema option with Zod, you need Zod v4 (zod@^4.0.0):
import { z } from 'zod';
Note that neither direct Zod v3 schemas nor the zod/v4 subpath export from the Zod v3 package are supported by the new configSchema option. While the zod/v4 subpath exposes the Zod v4 API surface, the resulting schema objects do not support the JSON Schema conversion that configSchema requires. A full migration to the zod v4 package is needed. Direct Zod v3 schemas only work with the deprecated config.schema callback format.
The deprecated createSchemaFromZod helper has been removed from @backstage/frontend-plugin-api.
See the 1.50 migration documentation for more information.
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:
tabs prop now uses HeaderNavTabItem[] instead of HeaderTab[]. Tabs render as a <nav> element with links instead of role="tablist". A new activeTabId prop controls which tab is highlighted, with automatic route-based detection when omitted.href resolution: Tab href values are now resolved through the router context instead of being passed raw. Relative href values are resolved against the current route, and absolute values may be affected by the router's basename configuration.toolbarWrapper element. Update custom CSS targeting .bui-PluginHeaderToolbarWrapper to use .bui-PluginHeaderToolbar instead.Check the BUI Changelog for more details.
PermissionedRouteThe deprecated PermissionedRoute component has been removed from @backstage/plugin-permission-react. Use RequirePermission instead.
The deprecated SignalService and DefaultSignalService exports have been removed from @backstage/plugin-signals-node. Use SignalsService and DefaultSignalsService instead.
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 — use coreServices.permissionsRegistry directlyThe 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.
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.
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.
DialogApi.open() methodA 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.
Several plugin pages have been migrated to use Backstage UI components:
Header and Container, with the plugin title changed to "Documentation".Added a new action to get a user's notifications through the actions registry.
Contributed by @drodil in #33831.
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 functionA 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.
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 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.
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.
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.
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.
Several performance improvements have been made to the catalog backend:
EXISTS (correlated subquery) patterns instead of IN (subquery), enabling PostgreSQL semi-join optimizations and fixing NOT IN NULL-semantics pitfalls.getProcessableEntities method now correctly wraps SELECT ... FOR UPDATE SKIP LOCKED in a transaction.The deadlock fix was contributed by @walsm232 in #33481.
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.
humanizeEntityRef in favor of Catalog Presentation APIThe 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.
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.
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.
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.
SearchModal leaving the page in a broken state when closing. Contributed by @fcamgz in #31406.AwsS3UrlReader failing to read files from S3 buckets configured with custom endpoint hosts. Contributed by @wtravO in #33612..well-known/oauth-protected-resource resource URL to comply with RFC 9728 Section 7.3. Contributed by @vincentrit in #33855.MembersListCard now prefers metadata.title over metadata.name when displaying the group membership card. Contributed by @Parsifal-M in #33885.SingleInstanceGithubCredentialsProvider to return app credentials when getCredentials is called with a bare host URL.Kind field to the AboutCard. Tags moved before Type and Lifecycle, Kind placed after them.HostDiscovery now logs a warning when backend.baseUrl is set to a localhost address while NODE_ENV is production.This release does not contain any security fixes.
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.