Skip to content
ToolShedby Wasim Shaikh

Angular Route Config Builder

Build Angular Routes visually: loadComponent and loadChildren, functional guards and resolvers, titles and withComponentInputBinding. Copy app.routes.ts, feature routes, app.config.ts and the ng generate commands.

Start from:

Shorter lazy imports: loadComponent: () => import('./home/home'). Components need export default class.

provideRouter features

Bind path params, query params, data and resolved values to component inputs with the same name.

Animate navigations with the browser View Transitions API.

Restore scroll position on back/forward and scroll to #anchors.

Preload every lazy route in the background after the app starts (PreloadAllModules).

Use #/ URLs, for hosts that cannot rewrite every path to index.html.

Off writes withComponentInputBinding({ queryParams: false }).

Routes (7)

Edit route ''

loadComponent: the component loads in its own chunk on first visit.

Relative, no leading slash. '' for the default child, '**' for not-found.

Class Home, created by ng generate component.

Sets document.title.

A ResolveFn<string>; replaces the static title.

Guards, resolvers and data

Decides if the route matches at all; blocks lazy code from loading.

Runs before this route activates.

Runs before any child route activates.

Runs before leaving, e.g. unsaved forms.

key: resolverFn, comma-separated.

key: value, comma-separated. true/false and numbers stay unquoted.

Separate several guards with commas. Each one becomes a functional guard file you can generate with the commands below.

src/app/app.routes.ts
import { Routes } from '@angular/router';
import { authGuard } from './guards/auth-guard';

export const routes: Routes = [
  { path: '', loadComponent: () => import('./home/home').then((m) => m.Home), title: 'Home' },
  {
    path: 'login',
    loadComponent: () => import('./login/login').then((m) => m.Login),
    title: 'Sign in',
  },
  {
    path: 'admin',
    canMatch: [authGuard],
    loadChildren: () => import('./admin/admin.routes').then((m) => m.ADMIN_ROUTES),
  },
  {
    path: '**',
    loadComponent: () => import('./not-found/not-found').then((m) => m.NotFound),
    title: 'Page not found',
  },
];

Generate the files

Run these in your workspace to create every component, guard and resolver the routes import.

ng generate component home
ng generate component login
ng generate component admin/dashboard
ng generate component admin/user-list
ng generate component admin/user-edit
ng generate component not-found
ng generate guard guards/auth --implements=CanMatch
ng generate guard guards/unsaved-changes --implements=CanDeactivate
ng generate resolver resolvers/user

URLs this config serves

  • /Homelazy
  • /loginLoginlazy
  • /adminDashboardlazyauthGuard
  • /admin/usersUserListlazyauthGuard
  • /admin/users/:idUserEditlazyauthGuard
  • /**NotFoundlazy

Component inputs (withComponentInputBinding)

UserEdit

readonly id = input<string>();           // path param
readonly user = input<unknown>();        // resolver (userResolver)

Inputs with no matching key are set to undefined; query params bind by name too. Import input from @angular/core.

withComponentInputBinding docs

Build Angular Routes Without the Boilerplate

Modern Angular routing is all functions: lazy loadComponent imports instead of NgModules, functional guards and resolvers instead of classes, and withComponentInputBinding() instead of subscribing to ActivatedRoute. Lay out your routes as a tree, pick how each one loads, attach guards, resolvers and titles, and the builder writes app.routes.ts, a .routes.ts file for every lazy feature, app.config.ts with the router features you chose, a stub for every guard and resolver, and the ng generate commands that create the rest.

It also checks the config as you go: a wildcard that is not last, an empty-path redirect without pathMatch: 'full', a leading slash, or a guard used for two different roles. The generated code type-checks against @angular/router 22.

Route Properties Reference

PropertyWhat it does
pathURL segment(s), relative to the parent. '' is the default child, ':id' a param, '**' the not-found catch-all.
loadComponentLazy-loads one standalone component in its own chunk.
loadChildrenLazy-loads a whole array of child routes from a feature.routes.ts file.
componentAn eagerly bundled component, typically a layout shell with a <router-outlet>.
childrenNested routes rendered in the parent component’s <router-outlet>.
redirectTo / pathMatchSends a URL elsewhere. Empty-path redirects need pathMatch: 'full'.
titleSets document.title, as a string or a ResolveFn<string>.
canMatchCanMatchFn. Decides whether the route matches at all; false tries the next route and skips lazy loading.
canActivate / canActivateChildCanActivateFn / CanActivateChildFn. Run before the route or any child activates; return a UrlTree to redirect.
canDeactivateCanDeactivateFn<T>. Runs before leaving, e.g. to warn about unsaved changes.
resolveResolveFn<T> map. Navigation waits for the data, which is bound to inputs with withComponentInputBinding.
dataStatic values, also bound to inputs with withComponentInputBinding.

How to Use the Builder

  1. Start from an example such as Login + guarded lazy admin, or from an empty config.
  2. Add routes and child routes in the tree. Select one to set its path, how it loads, its title, guards, resolvers and data.
  3. Pick router features such as withComponentInputBinding or withViewTransitions, and the file naming your project uses.
  4. Copy each file into src/app, then run the ng generate commands to create the components, guards and resolvers.

Frequently Asked Questions

Should I use loadComponent or component?
Use loadComponent for most pages. The component is split into its own chunk and only downloads when someone visits the route, which keeps the initial bundle small. Use component for things every visitor needs right away, such as a layout shell that wraps child routes.
When do I use loadChildren instead of loadComponent?
Use loadChildren for a whole area of the app with several routes, such as /admin. Its routes live in their own feature.routes.ts file, so none of that area is downloaded until the first visit. Put a canMatch guard on it and the code is not even fetched for users who are not allowed in.
What is the difference between canMatch and canActivate?
canMatch runs while the router is matching URLs. If it returns false, the router skips the route and tries the next one, and a lazy route is never loaded. canActivate runs after a route has matched, just before it activates. canLoad is deprecated; canMatch replaces it.
What does withComponentInputBinding do?
It binds route information straight to component inputs with the same name: path params such as :id, query params, static data and resolved values. Resolved values win when names collide. With it on, readonly id = input<string>() replaces ActivatedRoute.paramMap boilerplate. Inputs with no matching key are set to undefined.
Why does my empty-path redirect need pathMatch: full?
With the default 'prefix' matching, an empty path matches every URL, so { path: '', redirectTo: 'home' } would redirect everything. Angular rejects that config, and the builder flags it. Set pathMatch: 'full' so only the bare root URL redirects.
Which file names does the builder use?
By default it follows the Angular 20+ style guide that ng generate uses: hero-detail/hero-detail.ts with class HeroDetail, and guards/auth-guard.ts. Switch File naming to Classic for hero-detail.component.ts and auth.guard.ts; the ng generate commands then add --type=component and --type-separator=. to match.

Sources & Official Resources

Route properties, router features and generated file names follow the official Angular documentation. Last reviewed against Angular 22.

Need other ng commands? Use the Angular CLI Command Builder. Still on NgModule routing? The Angular Upgrade Planner lists the steps to reach v22. Browse all Angular tools.