Skip to content

Upgrading @angular/router 16 to 17

Breaking16.2.12 → 17.3.12Breaking25Platform7Deprecated9New76Changed21Fixed309Other3

BreakingUpgrade verdict

22 breaking changes and 6 platform requirement changes.

  • You can no longer change a signal's value in place with mutate. Use update and return a new value instead.
  • Two old compiler options are gone; code setting them must stop using them.
  • The mutate function is no longer part of the public signals API.
  • The urlHandlingStrategy property is no longer exposed on the Router.
Top 5 of 36 that need code or config changes

Node.js requirement changed in 17.0.0-rc.2: ^16.14.0 || >=18.10.0 → ^18.13.0 || >=20.9.0.

Breaking22
Removes the mutate method from the WritableSignal interface and public API; use update with immutable changes instead.
WritableSignalmutateupdate
Removes deprecated CompilerOptions.useJit and CompilerOptions.missingTranslation.
CompilerOptions.useJitCompilerOptions.missingTranslation
Drops the mutate function from the signals public API.
mutate
Removes urlHandlingStrategy from public Router properties.
RouterurlHandlingStrategy
Removes deprecated Router properties.
Router
Removes the deprecated setupTestingRouter function.
setupTestingRouter
Removes malformedUriErrorHandler from ExtraOptions.
ExtraOptionsmalformedUriErrorHandler
REMOVE_STYLES_ON_COMPONENT_DESTROY now defaults to true, removing component CSS from the DOM on destroy.
REMOVE_STYLES_ON_COMPONENT_DESTROY
Removes the withNoDomReuse() function from the public API.
withNoDomReuse()provideClientHydration()ngSkipHydration
Absolute redirects no longer prevent further redirects, which may require route config adjustments to avoid infinite redirects.
Routes with loadComponent no longer cause child routes to inherit data by default; paramsInheritanceStrategy defaults to emptyOnly.
loadComponentparamsInheritanceStrategy
Removes urlHandlingStrategy from the Router public API; configure it via provideRouter or RouterModule.forRoot.
urlHandlingStrategyprovideRouterRouterModule.forRoot
Removes canceledNavigationResolution, paramsInheritanceStrategy, titleStrategy, urlUpdateStrategy and malformedUriErrorHandler from the Router public API.
canceledNavigationResolutionparamsInheritanceStrategytitleStrategyurlUpdateStrategymalformedUriErrorHandlerprovideRouterRouterModule.forRoot
malformedUriErrorHandler is no longer available in RouterModule.forRoot options; handle URL parse errors in UrlSerializer.parse.
malformedUriErrorHandlerRouterModule.forRootUrlSerializer.parse
Removes the withNoDomReuse function from the public API.
withNoDomReuseprovideClientHydrationngSkipHydration
NgSwitch now defaults to the === equality operator instead of ==.
NgSwitch
Enables removal of styles on component destroy by default via REMOVE_STYLES_ON_COMPONENT_DESTROY set to true.
REMOVE_STYLES_ON_COMPONENT_DESTROY
Disallows afterRender in reactive contexts.
afterRender
Disallows using effect inside reactive contexts.
effect
Dynamically created OnPush components now refresh host bindings and run ngDoCheck only when dirty.
OnPushngDoCheckComponentRefmarkForCheckdetectChangesChangeDetectorRef
Removes the setupTestingRouter function; use RouterModule.forRoot or provideRouter to set up the Router for tests.
setupTestingRouterRouterModule.forRootprovideRouter
Disallows deep and legacy zone.js dist/ imports and removes zone-testing-bundle and zone-testing-node-bundle from the package.
zone.jszone.js/testingzone-testing-bundlezone-testing-node-bundle
Platform6
Adds support for TypeScript 5.4.
Adds support for TypeScript 5.3.
Removes support for Node.js v16.
Drops support for older TypeScript versions.
TypeScript
Supports TypeScript 5.2.
Drops support for TypeScript versions older than 5.2.
Deprecated8
Deprecates AnimationDriver.NOOP.
AnimationDriver.NOOP
Deprecates swapping out the context object for EmbeddedViewRef and warns on the deprecated NgProbeToken.
EmbeddedViewRefObject.assignProxyNgTemplateOutletNgProbeToken
Deprecates ChangeDetectorRef.checkNoChanges.
ChangeDetectorRef.checkNoChanges
Deprecates allowing the full context object to be replaced in EmbeddedViewRef.
EmbeddedViewRef
Deprecates the NgProbeToken.
NgProbeToken
Deprecates the AnimationDriver.NOOP symbol in favor of NoopAnimationDriver.
AnimationDriver.NOOPNoopAnimationDriver
Deprecates ChangeDetectorRef.checkNoChanges; tests should use ComponentFixture instead.
ChangeDetectorRef.checkNoChangesComponentFixtureChangeDetectorRef
Deprecates ChangeDetectorRef.checkNoChanges.
ChangeDetectorRef.checkNoChanges

Generated by DepDelta from published .d.ts files. Not mixed with prose notes.

  • removed: const enum EventType
  • removed: const enum NavigationCancellationCode
  • removed: const enum NavigationSkippedCode
  • removed: property ExtraOptions.malformedUriErrorHandler?: (error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree
  • removed: property Router.canceledNavigationResolution: 'replace' | 'computed'
  • removed: property Router.malformedUriErrorHandler: (error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree
  • removed: property Router.paramsInheritanceStrategy: 'emptyOnly' | 'always'
  • removed: property Router.titleStrategy?: TitleStrategy
  • removed: property Router.urlHandlingStrategy: UrlHandlingStrategy
  • removed: property Router.urlUpdateStrategy: 'deferred' | 'eager'
  • removed: readonly property Router.routerState: RouterState
  • changed: function withHashLocation(): RouterConfigurationFeature → function withHashLocation(): RouterHashLocationFeature
  • changed: method CanActivate.canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree → method CanActivate.canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): MaybeAsync<GuardResult>
  • changed: method CanActivateChild.canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree → method CanActivateChild.canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): MaybeAsync<GuardResult>
  • changed: method CanDeactivate.canDeactivate(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree → method CanDeactivate.canDeactivate(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot): MaybeAsync<GuardResult>
  • changed: method CanLoad.canLoad(route: Route, segments: UrlSegment[]): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree → method CanLoad.canLoad(route: Route, segments: UrlSegment[]): MaybeAsync<GuardResult>
  • changed: method CanMatch.canMatch(route: Route, segments: UrlSegment[]): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree → method CanMatch.canMatch(route: Route, segments: UrlSegment[]): MaybeAsync<GuardResult>
  • changed: method Resolve.resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T> | Promise<T> | T → method Resolve.resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): MaybeAsync<T>
  • changed: property NavigationBehaviorOptions.onSameUrlNavigation?: Extract<OnSameUrlNavigation, 'reload'> → property NavigationBehaviorOptions.onSameUrlNavigation?: OnSameUrlNavigation
  • changed: static property RouterLink.ɵdir: i0.ɵɵDirectiveDeclaration<RouterLink, '[routerLink]', never, { 'target': { 'alias': 'target'; 'required': false }; 'queryParams': { 'alias': 'queryParams'; 'required': false }; 'fragment': { 'alias': 'fragment'; 'required': false }; 'queryParamsHandling': { 'alias': 'queryParamsHandling'; 'required': false }; 'state': { 'alias': 'state'; 'required': false }; 'rela… → static property RouterLink.ɵdir: i0.ɵɵDirectiveDeclaration<RouterLink, '[routerLink]', never, { 'target': { 'alias': 'target'; 'required': false }; 'queryParams': { 'alias': 'queryParams'; 'required': false }; 'fragment': { 'alias': 'fragment'; 'required': false }; 'queryParamsHandling': { 'alias': 'queryParamsHandling'; 'required': false }; 'state': { 'alias': 'state'; 'required': false }; 'info…
  • changed: type CanActivateChildFn = (childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) => Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree → type CanActivateChildFn = (childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) => MaybeAsync<GuardResult>
  • changed: type CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree → type CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => MaybeAsync<GuardResult>
  • changed: type CanDeactivateFn<T> = (component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot) => Observable<boolean | UrlTree> | Prom… → type CanDeactivateFn<T> = (component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot) => MaybeAsync<GuardResult>
  • changed: type CanLoadFn = (route: Route, segments: UrlSegment[]) => Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree → type CanLoadFn = (route: Route, segments: UrlSegment[]) => MaybeAsync<GuardResult>
  • changed: type CanMatchFn = (route: Route, segments: UrlSegment[]) => Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree → type CanMatchFn = (route: Route, segments: UrlSegment[]) => MaybeAsync<GuardResult>
  • changed: type ResolveFn<T> = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => Observable<T> | Promise<T> | T → type ResolveFn<T> = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => MaybeAsync<T>
  • added: enum EventType
  • added: enum NavigationCancellationCode
  • added: enum NavigationSkippedCode
  • added: function withViewTransitions(options?: ViewTransitionsFeatureOptions): ViewTransitionsFeature
  • added: get Router.routerState(): RouterState_2
  • added: interface ViewTransitionInfo
  • added: interface ViewTransitionsFeatureOptions
  • added: property ExtraOptions.enableViewTransitions?: boolean
  • added: property RouterConfigOptions.resolveNavigationPromiseOnError?: boolean
  • added: property RouterLink.info?: unknown
  • added: property RouterLinkWithHref.info?: unknown
  • added: property ViewTransitionInfo.from: ActivatedRouteSnapshot
  • added: property ViewTransitionInfo.to: ActivatedRouteSnapshot
  • added: property ViewTransitionInfo.transition: { finished: Promise<void>; ready: Promise<void>; updateCallbackDone: Promise<void>; skipTransition(): void }
  • added: property ViewTransitionsFeatureOptions.onViewTransitionCreated?: (transitionInfo: ViewTransitionInfo) => void
  • added: property ViewTransitionsFeatureOptions.skipInitialTransition?: boolean
  • added: readonly property NavigationBehaviorOptions.info?: unknown
  • added: type GuardResult = boolean | UrlTree
  • added: type MaybeAsync<T> = T | Observable<T> | Promise<T>
  • added: type ViewTransitionsFeature = RouterFeature<RouterFeatureKind.ViewTransitionsFeature>
  • removed: function setupTestingRouter(urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location_2, compiler: Compiler, injector: Injector, routes: Route[][], opts?: ExtraOptions | UrlHandlingStrategy | null, urlHandlingStrategy?: UrlHandlingStrategy, routeReuseStrategy?: RouteReuseStrategy, titleStrategy?: TitleStrategy): Router
  • changed: const RouterUpgradeInitializer: { provide: InjectionToken<((compRef: ComponentRef<any>) => void)[]>; multi: boolean; useFactory: (ngUpgrade: UpgradeModule) => () => void; deps: (typeof Upgrad… → const RouterUpgradeInitializer: { provide: InjectionToken<readonly ((compRef: ComponentRef<any>) => void)[]>; multi: boolean; useFactory: (ngUpgrade: UpgradeModule) => () => void; deps: (type…