Upgrading @angular/router 21 to 22
Breaking21.2.25 → 22.2.4Breaking26Security33Platform3Deprecated7New84Changed29Fixed366Other5
Fetching 57 releases from GitHub…56 / 57
BreakingUpgrade verdict
23 breaking changes and 3 platform requirement changes and 33 security fixes.
In plain terms
- Templates relying on old shadow DOM selector syntax will no longer work.
- Apps depending on the old shadow CSS polyfills must migrate to supported encapsulation.
- Renames `TestBed.getFixture` to `TestBed.getLastFixture` and updates the implementation.
- Removes checkNoChanges from the public API.
Must act Top 5 of 66 that need code or config changes
Node.js requirement changed in 22.0.0-rc.2: ^20.19.0 || ^22.12.0 || >=24.0.0 → ^22.22.3 || ^24.15.0 || >=26.0.0.
What you must change
Breaking23
Removes dedicated support for legacy shadow DOM selectors.
Removes deprecated shadow CSS encapsulation polyfills.
Renames
TestBed.getFixture to TestBed.getLastFixture and updates the implementation.TestBed.getFixtureTestBed.getLastFixtureRemoves checkNoChanges from the public API.
checkNoChangesRemoves createNgModuleRef.
createNgModuleRefRemoves ComponentFactoryResolver and ComponentFactory from the API surface.
ComponentFactoryResolverComponentFactoryRemoves string support from min and max validation rules.
minmaxRemoves the Hammer integration.
HammerRemoves the deprecated
provideRoutes function.provideRoutesDeprecated
getAngularLib/setAngularLib are removed; use getAngularJSGlobal/setAngularJSGlobal instead.getAngularLibsetAngularLibgetAngularJSGlobalsetAngularJSGlobalparamsInheritanceStrategy now defaults to 'always' instead of 'emptyOnly', so route parameters are inherited from all parent routes.paramsInheritanceStrategyprovideRoutes() is removed; use provideRouter() or the ROUTES multi token instead.provideRoutes()provideRouter()ROUTESRemoves string value support from the min and max validation rules; bound values must be numbers or null.
minmaxThe second argument of appRef.bootstrap no longer accepts any; the element passed must not be nullable.
ApplicationRef.bootstrapRemoves styles when they appear no longer used by an associated host, which may leave other DOM unstyled.
ViewEncapsulation.EmulatedRemoves Hammer integration.
HammerRemoves createNgModuleRef; use createNgModule instead.
createNgModuleRefcreateNgModuleUses
FetchBackend as the default HttpBackend implementation.FetchBackendHttpBackendThe return type of
TitleStrategy.getResolvedTitleForRoute now reflects that it returns only string or undefined.TitleStrategy.getResolvedTitleForRouteThe
currentSnapshot parameter in CanMatchFn and the canMatch method of CanMatch is now required.CanMatchFnCanMatchcanMatchcurrentSnapshotDisables the nullishCoalescingNotNullable and optionalChainNotNullable diagnostics on ng update, which now trigger on existing projects.
nullishCoalescingNotNullableoptionalChainNotNullableElements with multiple matching selectors now throw at compile time.
Reverts support for nested animations in core.
Security33
Hardens param encoding against prototype pollution.
Hardens JIT against prototype pollution.
Blocks dangerous data: and vbscript: URLs in the URL sanitizer.
Extends the data: URL allowlist for non-executable MIME types.
@angular/router: Denial of Service via Unmatched Empty-Path Outlet Route Matching in Server-Side Rendering (SSR)
High@angular/router: Denial of Service via RouterLink Query Parameter Retention in Server-Side Rendering (SSR)
HighAngular Server-Side Rendering (SSR): Denial of Service via Numeric URL Matrix Parameters
HighRejects prefixed SVG script hosts.
Prevents TransferState prototype pollution.
TransferStateDisallows event handler attributes in Meta.
MetaRejects prefixed SVG script hosts.
Hardens platform location origin validation during SSR.
Prevents ReDoS in SOURCEMAP_URL_REGEXP in platform-browser.
SOURCEMAP_URL_REGEXPGuards against DOM clobbering in declareExperimentalWebMcpTool.
declareExperimentalWebMcpToolTreats iframe credentialless as security-sensitive.
Prevents prototype pollution in formatDateTime.
formatDateTimeUses cryptographically secure SHA-256 for transfer cache key generation.
Sanitizes href and xlink:href attributes of any element in the MathML namespace.
hrefxlink:hrefSanitizes two-way properties.
Hardens TransferState restoration against DOM clobbering.
TransferStateHardens FormGroup control lookups against prototype shadowing.
FormGroupHardens platform location origin validation during SSR.
Strips sensitive headers on cross-origin redirects in service-worker.
Sanitizes dynamic href and xlink:href bindings on SVG a elements.
hrefxlink:hrefUses Object.create(null) for LOCALE_DATA as a hardening measure.
LOCALE_DATAThrows on suspicious URLs and restricts protocol-relative URLs in platform-server.
Prevents SSRF bypasses via backslash URLs in HttpClient.
HttpClientSecures location and document initialization against SSRF and path hijack.
Validates security-sensitive attributes in i18n bindings.
Prevents SSRF bypasses via protocol-relative and backslash URLs.
Validates the locale in getOutputPathFn to prevent path traversal.
getOutputPathFnSanitizes translated form attributes in core.
Sanitizes translated attribute bindings with interpolations.
Platform3
Adds support for Node.js 26.0.0.
Drops support for TypeScript 5.9.
Drops Node.js v20 support; minimum supported Node.js versions are now v22.22.0 and v24.13.1.
Deprecations to plan for
Deprecated7
Deprecates JSONP support.
jsonpDeprecates
HttpClient.jsonp, HttpClientJsonpModule, and related JSONP classes and functions in favor of standard HTTP requests.HttpClient.jsonpHttpClientJsonpModuleDeprecates JSONP support in HttpClient.
HttpClient.jsonpHttpClientJsonpModuleDeprecates ServerXhr in @angular/platform-server.
ServerXhrDeprecates XHR support in @angular/platform-server in favor of standard fetch APIs.
@angular/platform-serverwithFetch is now deprecated and can be safely removed.withFetchThe
reportProgress option is deprecated; use reportUploadProgress and reportDownloadProgress instead.reportProgressreportUploadProgressreportDownloadProgressAPI changes
Generated by DepDelta from published .d.ts files. Not mixed with prose notes.
- removed:
interface DefaultExport<T> - removed:
property DefaultExport.default: T - changed:
class RedirectCommand → class RedirectCommand extends Error - changed:
method CanMatch.canMatch(route: Route, segments: UrlSegment[], currentSnapshot?: PartialMatchRouteSnapshot): MaybeAsync<GuardResult> → method CanMatch.canMatch(route: Route, segments: UrlSegment[], currentSnapshot: PartialMatchRouteSnapshot): MaybeAsync<GuardResult> - changed:
property ExtraOptions.bindToComponentInputs?: boolean → property ExtraOptions.bindToComponentInputs?: boolean | ComponentInputBindingOptions - changed:
property RouterLinkActive.routerLinkActiveOptions: { exact: boolean } | Partial<IsActiveMatchOptions> → property RouterLinkActive.routerLinkActiveOptions: { exact: boolean } | Partial<IsActiveMatchOptions> | null | undefined - changed:
set RouterLinkActive.routerLinkActive(data: string[] | string) → set RouterLinkActive.routerLinkActive(data: string[] | string | null | undefined) - changed:
static property RouteReuseStrategy.ɵprov: i0.ɵɵInjectableDeclaration<RouteReuseStrategy> → static property RouteReuseStrategy.ɵprov: i0.ɵɵInjectableDeclaration<any> - changed:
static property Router.ɵprov: i0.ɵɵInjectableDeclaration<Router> → static property Router.ɵprov: i0.ɵɵInjectableDeclaration<any> - changed:
static property UrlSerializer.ɵprov: i0.ɵɵInjectableDeclaration<UrlSerializer> → static property UrlSerializer.ɵprov: i0.ɵɵInjectableDeclaration<any> - changed:
type CanMatchFn = (route: Route, segments: UrlSegment[], currentSnapshot?: PartialMatchRouteSnapshot) => MaybeAsync<GuardResult> → type CanMatchFn = (route: Route, segments: UrlSegment[], currentSnapshot: PartialMatchRouteSnapshot) => MaybeAsync<GuardResult> - added:
function containsTree(container: UrlTree, containee: UrlTree, options?: Partial<IsActiveMatchOptions>): boolean - added:
interface ComponentInputBindingOptions - added:
interface ResourceContext - added:
method RouteReuseStrategy.retrieveStoredRouteHandles?(): Array<DetachedRouteHandle> - added:
method RouteReuseStrategy.shouldDestroyInjector?(route: Route): boolean - added:
property ActivatedRoute.resources?: ResourceResult - added:
property ActivatedRouteSnapshot.resources?: ResourceResult - added:
property ComponentInputBindingOptions.queryParams?: boolean - added:
property ComponentInputBindingOptions.unmatchedInputBehavior?: 'alwaysUndefined' | 'undefinedIfStale' - added:
property ResourceContext.data: Signal<Record<string, any>> - added:
property ResourceContext.fragment: Signal<string | null> - added:
property ResourceContext.params: Signal<Params> - added:
property ResourceContext.queryParams: Signal<Params> - added:
property Route.resources?: (ctx: ResourceContext) => ResourceResult | Promise<ResourceResult> - added:
property RouterLink.browserUrl: i0.InputSignal<string | UrlTree | undefined> - added:
type ResourceResult = Record<string, Resource<unknown> & Pick<WritableResource<unknown>, 'reload'>>
- removed:
export { DefaultExport } from './_router_module-chunk' - removed:
function provideRoutes(routes: Routes): Provider[] - changed:
function withComponentInputBinding(): ComponentInputBindingFeature → function withComponentInputBinding(options?: ComponentInputBindingOptions): ComponentInputBindingFeature - changed:
function withExperimentalAutoCleanupInjectors(): ExperimentalAutoCleanupInjectorsFeature → function withExperimentalAutoCleanupInjectors(): AutoCleanupInjectorsFeature - changed:
method TitleStrategy.getResolvedTitleForRoute(snapshot: ActivatedRouteSnapshot): any → method TitleStrategy.getResolvedTitleForRoute(snapshot: ActivatedRouteSnapshot): string | undefined - changed:
static property ChildrenOutletContexts.ɵprov: i0.ɵɵInjectableDeclaration<ChildrenOutletContexts> → static property ChildrenOutletContexts.ɵprov: i0.ɵɵInjectableDeclaration<any> - changed:
static property DefaultTitleStrategy.ɵprov: i0.ɵɵInjectableDeclaration<DefaultTitleStrategy> → static property DefaultTitleStrategy.ɵprov: i0.ɵɵInjectableDeclaration<any> - changed:
static property NoPreloading.ɵprov: i0.ɵɵInjectableDeclaration<NoPreloading> → static property NoPreloading.ɵprov: i0.ɵɵInjectableDeclaration<any> - changed:
static property PreloadAllModules.ɵprov: i0.ɵɵInjectableDeclaration<PreloadAllModules> → static property PreloadAllModules.ɵprov: i0.ɵɵInjectableDeclaration<any> - changed:
static property RouterPreloader.ɵprov: i0.ɵɵInjectableDeclaration<RouterPreloader> → static property RouterPreloader.ɵprov: i0.ɵɵInjectableDeclaration<any> - changed:
static property TitleStrategy.ɵprov: i0.ɵɵInjectableDeclaration<TitleStrategy> → static property TitleStrategy.ɵprov: i0.ɵɵInjectableDeclaration<any> - changed:
static property UrlHandlingStrategy.ɵprov: i0.ɵɵInjectableDeclaration<UrlHandlingStrategy> → static property UrlHandlingStrategy.ɵprov: i0.ɵɵInjectableDeclaration<any> - added:
export { ComponentInputBindingOptions } - added:
export { DefaultExport } from '@angular/core' - added:
export { ResourceContext } from './_router_module-chunk' - added:
export { ResourceResult } from './_router_module-chunk' - added:
export { containsTree } from './_router_module-chunk' - added:
function nonBlocking<T, R extends Resource<T>>(res: R): R - added:
function withAutoCleanupInjectors(): AutoCleanupInjectorsFeature - added:
function withRouterResources(): RouterResourcesFeature - added:
type AutoCleanupInjectorsFeature = RouterFeature<RouterFeatureKind.AutoCleanupInjectorsFeature> - added:
type RouterResourcesFeature = RouterFeature<RouterFeatureKind.RouterResourcesFeature>