Compatibility layer for migrating from Backstage's legacy frontend system to the new frontend system
npx @tessl/cli install tessl/npm-backstage--core-compat-api@0.5.0The Backstage Core Compat API provides a comprehensive compatibility layer that enables seamless migration from Backstage's legacy frontend system to the new frontend plugin system. It offers bidirectional compatibility, allowing legacy APIs to work in new apps and new APIs to work in legacy apps, making incremental migration possible without requiring complete rewrites.
npm install @backstage/core-compat-apiimport {
compatWrapper,
convertLegacyApp,
convertLegacyAppRoot,
convertLegacyPlugin,
convertLegacyRouteRef
} from "@backstage/core-compat-api";For CommonJS:
const {
compatWrapper,
convertLegacyApp,
convertLegacyPlugin
} = require("@backstage/core-compat-api");import {
compatWrapper,
convertLegacyPlugin,
convertLegacyRouteRef
} from "@backstage/core-compat-api";
import { createFrontendPlugin } from "@backstage/frontend-plugin-api";
// Wrap components for bidirectional compatibility
const WrappedComponent = () => compatWrapper(<MyLegacyComponent />);
// Convert legacy plugin to new system
const newPlugin = convertLegacyPlugin(legacyPlugin, {
extensions: [/* additional extensions */]
});
// Convert route references
const newRouteRef = convertLegacyRouteRef(legacyRouteRef);The Backstage Core Compat API is built around several key components:
compatWrapper provides bidirectional API bridge between old and new systemsconvertLegacyApp* functions transform entire legacy apps to new frontend modulesconvertLegacyPlugin migrates individual plugins to the new systemconvertLegacyRouteRef* functions handle route reference conversionsBidirectional compatibility provider that automatically detects the app context and enables legacy APIs in new apps and new APIs in legacy apps.
function compatWrapper(element: ReactNode): JSX.Element;Complete app migration utilities for converting legacy Backstage applications to the new frontend plugin system, including support for app options, components, and configurations.
function convertLegacyAppRoot(
rootElement: JSX.Element,
options?: ConvertLegacyAppRootOptions
): (FrontendPlugin | FrontendModule)[];
function convertLegacyAppOptions(
options?: ConvertLegacyAppOptionsParams
): FrontendModule;Plugin migration utilities for converting individual legacy plugins to the new frontend plugin system, preserving APIs, routes, and feature flags.
function convertLegacyPlugin(
legacyPlugin: LegacyBackstagePlugin,
options: { extensions: ExtensionDefinition[] }
): NewBackstagePlugin;
function convertLegacyPageExtension(
LegacyExtension: ComponentType<{}>,
overrides?: { name?: string; path?: string }
): ExtensionDefinition;Route reference translation system that handles conversion between legacy and new route reference types, supporting RouteRef, SubRouteRef, and ExternalRouteRef.
function convertLegacyRouteRef<T extends LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef>(
routeRef: T
): ToNewRouteRef<T>;
function convertLegacyRouteRefs<TRefs extends Record<string, RouteRef>>(
refs: TRefs
): { [KName in keyof TRefs]: ToNewRouteRef<TRefs[KName]> };
type ToNewRouteRef<T> = T extends LegacyRouteRef<infer IParams>
? RouteRef<IParams>
: T extends LegacySubRouteRef<infer IParams>
? SubRouteRef<IParams>
: T extends LegacyExternalRouteRef<infer IParams>
? ExternalRouteRef<IParams>
: never;Analytics implementations that provide compatibility between legacy and new analytics systems, supporting multiple analytics providers and no-operation implementations.
class MultipleAnalyticsApi {
static fromApis(actualApis: (AnalyticsApi | NewAnalyticsApi)[]): MultipleAnalyticsApi;
captureEvent(event: AnalyticsEvent | NewAnalyticsEvent): void;
}
class NoOpAnalyticsApi {
captureEvent(_event: AnalyticsEvent | NewAnalyticsEvent): void;
}interface ConvertLegacyAppRootOptions {
entityPage?: JSX.Element;
}
type ConvertLegacyAppOptions = ConvertLegacyAppRootOptions; // deprecated
type ToNewRouteRef<T extends LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef> =
T extends LegacyRouteRef<infer IParams> ? RouteRef<IParams>
: T extends LegacySubRouteRef<infer IParams> ? SubRouteRef<IParams>
: T extends LegacyExternalRouteRef<infer IParams> ? ExternalRouteRef<IParams>
: never;