Skip to main content

Route Configuration

Route configuration defines the mapping between URL paths and components in your Angular application. Routes are defined using the Routes type and Route interface.

Import

import { Routes, Route } from '@angular/router';

Routes Type

type Routes = Route[];
An array of Route objects that defines the routing configuration for the application.

Route Interface

interface Route {
  // Path Configuration
  path?: string;
  pathMatch?: 'prefix' | 'full';
  matcher?: UrlMatcher;

  // Component Configuration
  component?: Type<any>;
  loadComponent?: () => Promise<Type<any>>;
  redirectTo?: string | RedirectFunction;

  // Child Routes
  children?: Routes;
  loadChildren?: LoadChildren;

  // Named Outlets
  outlet?: string;

  // Guards
  canActivate?: Array<CanActivateFn | DeprecatedGuard>;
  canActivateChild?: Array<CanActivateChildFn | DeprecatedGuard>;
  canDeactivate?: Array<CanDeactivateFn<any> | DeprecatedGuard>;
  canMatch?: Array<CanMatchFn | DeprecatedGuard>;
  canLoad?: Array<CanLoadFn | DeprecatedGuard>; // deprecated

  // Data and Resolution
  data?: Data;
  resolve?: ResolveData;
  title?: string | Type<Resolve<string>> | ResolveFn<string>;

  // Additional Options
  runGuardsAndResolvers?: RunGuardsAndResolvers;
  providers?: Array<Provider | EnvironmentProviders>;
}

Route Properties

Path Configuration

path

path?: string
The URL path to match. Supports:
  • Static paths: 'home', 'about'
  • Dynamic parameters: 'users/:id', 'posts/:postId/comments/:commentId'
  • Wildcard: '**' (matches any URL)
  • Empty path: '' (matches without consuming URL segments)
Examples:
const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'users/:id', component: UserComponent },
  { path: 'products/:category/:productId', component: ProductComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: '**', component: NotFoundComponent }
];

pathMatch

pathMatch?: 'prefix' | 'full'
The path matching strategy:
  • 'prefix' (default): Matches when the URL starts with the path
  • 'full': Matches only when the URL exactly matches the path
Example:
const routes: Routes = [
  // Must match exact empty path for redirect
  { path: '', pathMatch: 'full', redirectTo: '/home' },
  // Prefix match allows child routes
  { path: 'admin', component: AdminComponent, children: [...] }
];
Always use pathMatch: 'full' when redirecting from an empty path, otherwise the redirect will apply to all URLs.

matcher

matcher?: UrlMatcher
A custom function for URL matching. Cannot be used with path. Type Definition:
type UrlMatcher = (
  segments: UrlSegment[],
  group: UrlSegmentGroup,
  route: Route
) => UrlMatchResult | null;

type UrlMatchResult = {
  consumed: UrlSegment[];
  posParams?: { [name: string]: UrlSegment };
};
Example:
import { UrlSegment } from '@angular/router';

// Match URLs ending with .html
export function htmlFilesMatcher(segments: UrlSegment[]) {
  return segments.length === 1 && segments[0].path.endsWith('.html')
    ? { consumed: segments }
    : null;
}

const routes: Routes = [
  { matcher: htmlFilesMatcher, component: HtmlViewerComponent }
];

Component Configuration

component

component?: Type<any>
The component to instantiate when the path matches. Example:
const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'users/:id', component: UserDetailComponent }
];

loadComponent

loadComponent?: () => Promise<Type<any> | DefaultExport<Type<any>>>
Lazy-load a standalone component. Examples:
const routes: Routes = [
  {
    path: 'admin',
    loadComponent: () => import('./admin/admin.component').then(m => m.AdminComponent)
  },
  // With default export, .then() can be omitted
  {
    path: 'profile',
    loadComponent: () => import('./profile/profile.component')
  }
];

redirectTo

redirectTo?: string | RedirectFunction
URL to redirect to when this path matches. Can be:
  • Absolute path: '/home'
  • Relative path: '../other'
  • Path with parameters: '/users/:id'
  • Function for conditional redirects: RedirectFunction
Examples:
const routes: Routes = [
  // Simple redirect
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  
  // Redirect with parameters
  { path: 'old-users/:id', redirectTo: '/users/:id' },
  
  // Conditional redirect function
  {
    path: 'dashboard',
    redirectTo: (route) => {
      const userService = inject(UserService);
      return userService.isAdmin() ? '/admin-dashboard' : '/user-dashboard';
    }
  }
];

Child Routes

children

children?: Routes
Nested child routes. Example:
const routes: Routes = [
  {
    path: 'products',
    component: ProductsComponent,
    children: [
      { path: '', component: ProductListComponent },
      { path: ':id', component: ProductDetailComponent },
      { path: ':id/edit', component: ProductEditComponent }
    ]
  }
];
Template for parent component:
<h1>Products</h1>
<router-outlet></router-outlet>

loadChildren

loadChildren?: LoadChildren
Lazy-load child routes. Type Definition:
type LoadChildren = () =>
  | Routes
  | Type<any>
  | Observable<Routes | Type<any>>
  | Promise<Routes | Type<any> | DefaultExport<Routes | Type<any>>>;
Examples:
const routes: Routes = [
  // Lazy load routes
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.routes').then(m => m.ADMIN_ROUTES)
  },
  
  // Lazy load NgModule (legacy)
  {
    path: 'legacy',
    loadChildren: () => import('./legacy/legacy.module').then(m => m.LegacyModule)
  },
  
  // With default export
  {
    path: 'dashboard',
    loadChildren: () => import('./dashboard/routes')
  }
];

Named Outlets

outlet

outlet?: string
Name of the RouterOutlet where the component should be rendered. Example:
const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'sidebar', component: SidebarComponent, outlet: 'side' },
  { path: 'popup', component: PopupComponent, outlet: 'popup' }
];
Template:
<router-outlet></router-outlet> <!-- primary outlet -->
<router-outlet name="side"></router-outlet>
<router-outlet name="popup"></router-outlet>
Navigate to named outlet:
router.navigate([{
  outlets: {
    primary: 'home',
    side: 'sidebar',
    popup: 'popup'
  }
}]);

Guards

canActivate

canActivate?: Array<CanActivateFn | DeprecatedGuard>
Guards that determine if the route can be activated. Example:
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';

export const authGuard: CanActivateFn = (route, state) => {
  const authService = inject(AuthService);
  const router = inject(Router);

  if (authService.isLoggedIn()) {
    return true;
  }

  return router.createUrlTree(['/login'], {
    queryParams: { returnUrl: state.url }
  });
};

const routes: Routes = [
  {
    path: 'admin',
    component: AdminComponent,
    canActivate: [authGuard]
  }
];

canActivateChild

canActivateChild?: Array<CanActivateChildFn | DeprecatedGuard>
Guards that determine if child routes can be activated. Example:
const routes: Routes = [
  {
    path: 'admin',
    component: AdminComponent,
    canActivateChild: [adminGuard],
    children: [
      { path: 'users', component: UsersComponent },
      { path: 'settings', component: SettingsComponent }
    ]
  }
];

canDeactivate

canDeactivate?: Array<CanDeactivateFn<any> | DeprecatedGuard>
Guards that determine if the route can be deactivated (e.g., unsaved changes). Example:
import { CanDeactivateFn } from '@angular/router';

export interface CanComponentDeactivate {
  canDeactivate: () => boolean | Promise<boolean>;
}

export const unsavedChangesGuard: CanDeactivateFn<CanComponentDeactivate> = (
  component
) => {
  return component.canDeactivate ? component.canDeactivate() : true;
};

const routes: Routes = [
  {
    path: 'edit',
    component: EditComponent,
    canDeactivate: [unsavedChangesGuard]
  }
];

canMatch

canMatch?: Array<CanMatchFn | DeprecatedGuard>
Guards that determine if the route configuration can be matched. Example:
import { inject } from '@angular/core';
import { CanMatchFn } from '@angular/router';
import { FeatureFlagService } from './feature-flag.service';

export const featureGuard: CanMatchFn = (route) => {
  const featureFlags = inject(FeatureFlagService);
  const requiredFeature = route.data?.['feature'];
  return featureFlags.isEnabled(requiredFeature);
};

const routes: Routes = [
  {
    path: 'beta-feature',
    component: BetaComponent,
    canMatch: [featureGuard],
    data: { feature: 'beta-feature' }
  },
  // Fallback if feature not enabled
  { path: 'beta-feature', component: ComingSoonComponent }
];

Data and Resolution

data

data?: Data
Static data associated with the route. Type:
type Data = { [key: string | symbol]: any };
Example:
const routes: Routes = [
  {
    path: 'products',
    component: ProductsComponent,
    data: { title: 'Products', breadcrumb: 'All Products', roles: ['user', 'admin'] }
  }
];

// Access in component
import { Component, inject, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({ /* ... */ })
export class ProductsComponent implements OnInit {
  private route = inject(ActivatedRoute);

  ngOnInit() {
    const data = this.route.snapshot.data;
    console.log(data['title']); // 'Products'
  }
}

resolve

resolve?: ResolveData
Data resolvers that pre-fetch data before route activation. Type:
type ResolveData = {
  [key: string]: ResolveFn<any> | DeprecatedResolve;
};

type ResolveFn<T> = (
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot
) => MaybeAsync<T | RedirectCommand>;
Example:
import { inject } from '@angular/core';
import { ResolveFn } from '@angular/router';
import { UserService, User } from './user.service';

export const userResolver: ResolveFn<User> = (route) => {
  const userService = inject(UserService);
  return userService.getUser(route.params['id']);
};

const routes: Routes = [
  {
    path: 'users/:id',
    component: UserDetailComponent,
    resolve: { user: userResolver }
  }
];

// Access resolved data in component
@Component({ /* ... */ })
export class UserDetailComponent implements OnInit {
  private route = inject(ActivatedRoute);

  ngOnInit() {
    const user = this.route.snapshot.data['user'];
    console.log(user);
  }
}

title

title?: string | Type<Resolve<string>> | ResolveFn<string>
Page title for the route. Examples:
const routes: Routes = [
  // Static title
  { path: 'home', component: HomeComponent, title: 'Home' },
  
  // Dynamic title with resolver
  {
    path: 'users/:id',
    component: UserComponent,
    title: (route) => `User ${route.params['id']}`
  }
];

Additional Options

runGuardsAndResolvers

runGuardsAndResolvers?: RunGuardsAndResolvers
Defines when guards and resolvers should run. Type:
type RunGuardsAndResolvers =
  | 'pathParamsChange'
  | 'pathParamsOrQueryParamsChange'
  | 'paramsChange'
  | 'paramsOrQueryParamsChange'
  | 'always'
  | ((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean);
Example:
const routes: Routes = [
  {
    path: 'search',
    component: SearchComponent,
    runGuardsAndResolvers: 'paramsOrQueryParamsChange',
    resolve: { results: searchResolver }
  }
];

providers

providers?: Array<Provider | EnvironmentProviders>
Dependency injection providers for this route and its children. Example:
import { Routes } from '@angular/router';
import { UserService } from './user.service';

const routes: Routes = [
  {
    path: 'admin',
    component: AdminComponent,
    providers: [UserService],
    children: [
      // Child routes can inject UserService
      { path: 'users', component: UsersComponent }
    ]
  }
];

Common Route Patterns

Basic Routes

const routes: Routes = [
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: 'home', component: HomeComponent },
  { path: 'about', component: AboutComponent },
  { path: 'contact', component: ContactComponent },
  { path: '**', component: NotFoundComponent }
];

Parameterized Routes

const routes: Routes = [
  { path: 'users/:id', component: UserDetailComponent },
  { path: 'posts/:postId/comments/:commentId', component: CommentComponent },
  { path: 'products/:category', component: ProductListComponent }
];

Nested Routes

const routes: Routes = [
  {
    path: 'dashboard',
    component: DashboardComponent,
    children: [
      { path: '', component: DashboardHomeComponent },
      { path: 'stats', component: StatsComponent },
      { path: 'reports', component: ReportsComponent }
    ]
  }
];

Lazy Loading

const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.routes').then(m => m.ADMIN_ROUTES),
    canMatch: [adminGuard]
  },
  {
    path: 'profile',
    loadComponent: () => import('./profile/profile.component'),
    canActivate: [authGuard]
  }
];

Protected Routes

const routes: Routes = [
  {
    path: 'admin',
    component: AdminLayoutComponent,
    canActivate: [authGuard, adminGuard],
    canActivateChild: [adminGuard],
    children: [
      { path: 'users', component: UsersComponent },
      { path: 'settings', component: SettingsComponent }
    ]
  }
];

Routes with Resolvers

const routes: Routes = [
  {
    path: 'product/:id',
    component: ProductComponent,
    resolve: {
      product: productResolver,
      reviews: reviewsResolver
    }
  }
];

See Also

Router Class

Router service API

Route Guards

Guard functions and interfaces

Routing Guide

Complete routing guide

Lazy Loading

Lazy loading feature modules