Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To add routing in Angular, you define a Routes array that maps URL paths to components, register it with provideRouter(routes), place a <router-outlet /> where routed pages should appear, and use routerLink for navigation. Navigation then happens inside the app without a full-page reload. The steps below follow Angular’s current routing guide, and the sections after them cover route order, nested views, lazy loading, and guards, including what guards cannot protect.

Which setup this guide follows

The examples use standalone components and the provideRouter configuration that Angular’s current routing documentation describes at angular.dev/guide/routing/define-routes. Projects built on NgModules register the same kind of route array through RouterModule instead, so check which architecture your project uses before copying code. Angular also publishes a versioned guide for v20 at v20.angular.dev/guide/routing/define-routes; route matching behaves the same way there, but if your project is on a different major version, read the guide for that version.

Set up routing step by step

  1. Define the routes. Create a Routes array that maps each URL path to a component. In Angular CLI projects, the conventional location is src/app/app.routes.ts.
    import { Routes } from '@angular/router';
    import { HomeComponent } from './home/home.component';
    import { UserComponent } from './user/user.component';
    import { NotFoundComponent } from './not-found/not-found.component';
    
    export const routes: Routes = [
      { path: '', component: HomeComponent },
      { path: 'user/:id', component: UserComponent },
      { path: '**', component: NotFoundComponent }
    ];
  2. Register the router. In the standalone application configuration (usually src/app/app.config.ts), add provideRouter(routes) to the providers array.
    import { ApplicationConfig } from '@angular/core';
    import { provideRouter } from '@angular/router';
    import { routes } from './app.routes';
    
    export const appConfig: ApplicationConfig = {
      providers: [provideRouter(routes)]
    };
  3. Render the active view. Import RouterOutlet into the component that should host routed pages, usually the root component, and place <router-outlet /> in its template. The router inserts the component that matches the current URL at that point. The Show routes with Outlets guide covers the rendering model in detail.
    import { Component } from '@angular/core';
    import { RouterOutlet } from '@angular/router';
    
    @Component({
      selector: 'app-root',
      imports: [RouterOutlet],
      template: `
        <nav>
          <a routerLink="/">Home</a>
        </nav>
        <router-outlet />
      `
    })
    export class AppComponent {}
  4. Add navigation with RouterLink. Import RouterLink into the component and use it on ordinary anchor elements. Angular Router handles the click, so the browser does not request a new page. The Navigate to routes guide explains the declarative approach.
    <a routerLink="/user/42">View user 42</a>
  5. Add dynamic and nested paths. A colon prefix turns a path segment into a parameter, as in user/:id. When only part of a screen should change, give the parent a children array and add a nested outlet to the parent’s template.
    export const routes: Routes = [
      {
        path: 'products',
        component: ProductsComponent,
        children: [
          { path: ':id', component: ProductDetailComponent }
        ]
      }
    ];
  6. Decide how routes load and who can enter them. Lazy-load noncritical routes to shrink the initial bundle, and use guards to control client-side navigation. Both decisions are covered in the sections below.

How Angular chooses a route

Angular uses a first-match strategy. It checks the routes in the order you list them and stops at the first one whose path fits the URL. A broad pattern placed early can therefore hide a more specific route that comes after it. Put specific paths such as user/new before parameterized ones such as user/:id, and keep the ** wildcard last so it catches only paths nothing else matched. The Define routes guide documents this ordering rule.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Path parameters and query parameters

Path parameters are part of the route definition. In user/:id, the segment is required for that route to match. Query parameters, the values after ? such as ?page=2, are separate URL state and are not declared in the route path. Read both through ActivatedRoute, which also exposes data attached to the route. Mixing them up is a common reason a value appears to be missing: a value meant as a path parameter that was written as a query string will not match :id.

Nested routes need an outlet in the parent

A child route only renders if its parent route is configured with children and the parent component contains a <router-outlet />. Without that nested outlet, the router has no placeholder to render the child view into, and the parent screen appears without the intended content.

Lazy loading: when to split a route out

A route can load its component on demand with loadComponent, which dynamically imports a standalone component when the route becomes active. This reduces the JavaScript included in the initial bundle, but each lazily loaded route adds a request the first time a user reaches it. Angular’s guidance is to consider eager loading for primary landing pages and lazy loading for other pages, while accounting for the cost of nested lazy-loading layers and your application’s performance needs. The official guidance at v20.angular.dev/guide/routing/define-routes gives this as general direction and does not set a universal size or timing threshold.

{
  path: 'reports',
  loadComponent: () => import('./reports/reports.component').then(m => m.ReportsComponent)
}

A practical way to decide is to keep the home page and the first screen a visitor sees in the main bundle, and lazy-load secondary areas such as admin tools, reports, or rarely visited settings pages. Check the build output and the network waterfall after the change to confirm the split is doing what you expected.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Guards: controlling navigation and its limits

Angular’s route guards run during navigation. The documented types are:

  • CanActivate, which decides whether a route can be entered.
  • CanActivateChild, which applies the same check to a route’s child routes.
  • CanDeactivate, which decides whether the user can leave a route, for example when a form has unsaved changes.
  • CanMatch, which decides whether a route definition is used at all.

A guard can return a boolean, a UrlTree or RedirectCommand to send the user elsewhere, or an observable or promise that resolves to one of those. CanMatch behaves differently from the others: when it returns false, the router moves on and tries other matching routes. That makes it useful for conditional alternatives, such as serving a different component for a feature flag.

Guards are a navigation feature, not a security boundary. Angular’s route guard documentation at angular.dev/guide/routing/route-guards states it directly:

Never rely on client-side guards as the sole source of access control.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The guide explains the reason: code running in the browser can be modified by the user, so a guard can always be bypassed on the client. Authorization must be enforced on the server, where each API request is checked against the user’s permissions.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting checklist

  • A route never matches. Check whether a broader path or ** appears earlier in the array. Move the specific route above it.
  • A child view is blank. Confirm the parent route has a children array and that the parent’s template includes <router-outlet />.
  • Clicking a link reloads the page. Confirm the anchor uses routerLink rather than a plain href, and that RouterLink is listed in the component’s imports.
  • A route parameter is undefined. Confirm the path declares the segment with a colon, such as :id, and that the link supplies it in the path rather than the query string.
  • A lazy route fails to load. Check the import path in loadComponent and that the target is a standalone component.

Next steps

Start with the three-file setup: routes, the application configuration, and a root template with an outlet. Once navigation works, add nested and lazy routes one at a time so that any route-order or outlet problem is easy to isolate.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.