Question
Angular RouterLink Error: Import RouterModule in the Correct NgModule
Question
In an Angular 2 application created with Angular CLI, the application shell renders a header above a <router-outlet>:
<!-- app.component.html -->
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
The header template contains a navigation link:
<!-- header.component.html -->
<a [routerLink]="['/signin']">Sign in</a>
Angular reports the following error:
Can't bind to 'routerLink' since it isn't a known property of 'a'.
AppRoutingModule imports and exports RouterModule, while HeaderComponent is declared in a separate LayoutModule. The signin route is configured in a feature routing module using RouterModule.forChild(). How can the header navigate to /signin, and why does Angular not recognize routerLink in this component?
Short Answer
You will learn that a component can use routerLink regardless of whether it is above or below a <router-outlet>. The error is caused by Angular's NgModule template scope: the NgModule that declares HeaderComponent must import RouterModule so that the RouterLink directive is available in the header template.
Concept
routerLink is not a built-in HTML property. It is an Angular directive supplied by RouterModule.
<a [routerLink]="['/signin']">Sign in</a>
When Angular compiles a component template, it checks the directives available in that component's template scope. In NgModule-based Angular applications, that scope comes from:
- the NgModule that declares the component, and
- the modules imported by that declaring NgModule.
In this case, HeaderComponent is declared by LayoutModule, not AppModule. Importing AppRoutingModule into AppModule makes routing directives available to templates declared in AppModule, but it does not automatically make them available to templates declared in LayoutModule.
The location of <app-header> relative to <router-outlet> is not the problem. A header, footer, sidebar, or any other component can contain router links. routerLink asks Angular's shared service to navigate; it does not require the component to be rendered inside the outlet.
Mental Model
Think of an NgModule as a classroom and directives as tools kept in that classroom.
RouterModule brings tools such as routerLink and router-outlet. AppModule may have those tools, but HeaderComponent belongs to the separate LayoutModule classroom. Unless LayoutModule imports RouterModule, the header's template cannot use the routerLink tool.
The <router-outlet> is like a display area where the router places the selected page. A navigation button does not have to be inside that display area. It only needs access to the router tool.
Syntax and Examples
Import RouterModule in every NgModule whose declared templates use routing directives.
// layout.module.ts
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { HeaderComponent } from './header/header.component';
import { FooterComponent } from './footer/footer.component';
@NgModule({
declarations: [HeaderComponent, FooterComponent],
imports: [RouterModule],
exports: [HeaderComponent, FooterComponent]
})
export class LayoutModule {}
The header can then use routerLink normally:
<!-- header.component.html -->
<nav>
<a =>Sign in
Profile
Step by Step Execution
Consider this module structure:
// app.module.ts
@NgModule({
imports: [
BrowserModule,
LayoutModule,
UsersModule,
AppRoutingModule
]
})
export class AppModule {}
// layout.module.ts
@NgModule({
declarations: [HeaderComponent, FooterComponent],
imports: [RouterModule],
exports: [HeaderComponent, FooterComponent]
})
export class LayoutModule {}
<!-- header.component.html -->
<a routerLink="/signin">Sign in</a>
What happens:
- Angular compiles
HeaderComponent. - It sees
routerLinkon the element.
Real World Use Cases
Routing links are commonly placed in shared layout components:
- Top navigation: links to dashboard, sign-in, account settings, and help pages.
- Sidebar menus: links to admin sections and nested application areas.
- Footers: links to privacy policies, terms, and contact pages.
- Breadcrumbs: links assembled from the current page hierarchy.
- Data tables: links to detail pages such as
/orders/1024. - Authentication UI: a sign-in link shown when no user session exists.
These components are often declared in a LayoutModule, SharedModule, or similar reusable module. Each such NgModule must import the directives its templates use.
Real Codebase Usage
In NgModule-based applications, teams usually organize routing this way:
// app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: 'signin', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
// users-routing.module.ts
const routes: Routes = [
{ path: 'signin', component: SigninComponent }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class UsersRoutingModule {}
Common Mistakes
Importing routing only in AppModule
This does not expose routerLink to components declared by another NgModule:
// Broken when HeaderComponent is declared in LayoutModule
@NgModule({
imports: [AppRoutingModule, LayoutModule]
})
export class AppModule {}
Fix: import RouterModule in LayoutModule.
@NgModule({
imports: [RouterModule]
})
export class LayoutModule {}
Calling forRoot() in a shared or layout module
// Do not do this in LayoutModule
imports: [RouterModule.forRoot([])]
forRoot() configures router providers and should run once. A second call can cause provider and configuration problems. Use plain instead.
Comparisons
| Approach | Main purpose | Where to use it |
|---|---|---|
RouterModule.forRoot(routes) | Creates the root router configuration and providers | Once, usually in AppRoutingModule |
RouterModule.forChild(routes) | Registers routes owned by a feature module | Feature routing modules such as UsersRoutingModule |
RouterModule | Makes routing directives available in templates | Modules declaring components that use routerLink or router-outlet |
routerLink="/signin" | Navigate to a fixed internal URL declaratively | Standard template links |
[routerLink]="['/users', id]" |
Cheat Sheet
// Root routing module: once per application
RouterModule.forRoot(routes)
// Feature routing module
RouterModule.forChild(featureRoutes)
// A module with components that use routerLink
imports: [RouterModule]
<!-- Fixed route -->
<a routerLink="/signin">Sign in</a>
<!-- Dynamic route segments -->
<a [routerLink]="['/users', userId]">User</a>
<!-- Active-link CSS class -->
<a routerLink="/signin" routerLinkActive="active">Sign in</a>
<!-- Routed component insertion point -->
<router-outlet></router-outlet>
Rules to remember:
- Import dependencies where a component is declared, not merely where it is used.
RouterModuleprovides template directives such as .
FAQ
Why does Angular say routerLink is not a known property?
Angular cannot find the RouterLink directive in the template scope of the component. Import RouterModule into the NgModule that declares that component.
Does a header need to be inside router-outlet to use routerLink?
No. A header can be above, below, or completely separate from the outlet. It only needs access to RouterModule in its declaring module.
Should LayoutModule import AppRoutingModule?
Usually no. LayoutModule only needs RouterModule to use routing directives. The root application module should own the routing configuration through AppRoutingModule.
What is the difference between forRoot() and forChild()?
forRoot() creates the main router configuration and providers once. forChild() adds routes from a feature module without creating another root router.
Why does show the not-found page?
Mini Project
Description
Build a small application shell with a persistent header and footer. The header contains Angular router links, while the selected page appears in the central <router-outlet>. This demonstrates that shared layout components can navigate even when they are outside routed content.
Goal
Create working /signin and /help navigation links in a header declared by a separate LayoutModule.
Requirements
Requirement 1
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.