
Angularâs routing system keeps getting better, and with Angular 19, CanMatch
has stepped up as a powerful tool for controlling access to routesâeven before theyâre activated. If youâre still relying only on CanActivate
, it might be time to upgrade your strategy.
In this article, Iâll walk you through whatâs new with CanMatch
in Angular 19, why it matters, and how to use it effectively for things like role-based access and feature flags.
âď¸ Whatâs New in Angular 19?
Angular 19 focuses heavily on performance and simplicity. With improved integration for standalone components and function-based guards, CanMatch
is now more efficient and easier to use than ever.
It lets you determine whether a route should even be matchedâbefore Angular starts building components or running expensive checks. That makes it a game-changer for access control and performance optimization.
đ What is CanMatch
, Exactly?
CanMatch
is a route guard that decides if a route should be considered during navigation. Unlike CanActivate
, which runs after the route has matched, CanMatch
works before that step, making it more efficient for conditional access.
⨠When to Use CanMatch
?
- â Control access based on roles or authentication
- đ Prevent unnecessary component instantiation
- đ§Š Enable/disable routes dynamically (feature flags, AB testing, etc.)
- đ§ź Simplify logic by avoiding nested guards
đ ď¸ Step-by-Step: How to Use CanMatch
in Angular 19
Step 1: Set Up an Auth Service
Youâll need a service to manage user authentication and roles:
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class AuthService {
private isAuthenticated = false;
private userRole: string | null = null;
login(role: string) {
this.isAuthenticated = true;
this.userRole = role;
}
logout() {
this.isAuthenticated = false;
this.userRole = null;
}
isUserAuthenticated(): boolean {
return this.isAuthenticated;
}
getUserRole(): string | null {
return this.userRole;
}
}
Step 2: Create a Function-Based CanMatch
Guard
Angular 19 encourages function-based guards (not class-based). Hereâs a simple role-based guard:
import { inject } from '@angular/core';
import { CanMatchFn, Route, UrlSegment } from '@angular/router';
import { AuthService } from './auth.service';
export const roleMatchGuard: CanMatchFn = (route: Route, segments: UrlSegment[]) => {
const authService = inject(AuthService);
const expectedRole = route.data?.['role'];
const userRole = authService.getUserRole();
return authService.isUserAuthenticated() && userRole === expectedRole;
};
Step 3: Add the Guard to Your Routes
Just drop the guard in using the canMatch
key:
import { Routes, provideRouter } from '@angular/router';
import { AdminComponent } from './admin/admin.component';
import { UserComponent } from './user/user.component';
import { roleMatchGuard } from './role-match.guard';
const routes: Routes = [
{ path: 'admin', component: AdminComponent, canMatch: [roleMatchGuard], data: { role: 'admin' } },
{ path: 'user', component: UserComponent, canMatch: [roleMatchGuard], data: { role: 'user' } }
];
export const appRouting = provideRouter(routes);
đ§Ş Bonus Use Case: Feature Flags with CanMatch
One of my favorite uses of CanMatch
is toggling features dynamically. You can easily restrict access based on a feature flag.
Feature Flag Guard:
import { CanMatchFn, Route, UrlSegment } from '@angular/router';
const featureFlags = { newFeature: true };
export const featureFlagGuard: CanMatchFn = (route: Route, segments: UrlSegment[]) => {
const requiredFeature = route.data?.['featureFlag'];
return featureFlags[requiredFeature] ?? false;
};
Apply to Routes:
{
path: 'new-feature',
component: NewFeatureComponent,
canMatch: [featureFlagGuard],
data: { featureFlag: 'newFeature' }
}
âď¸ CanMatch
vs. CanActivate
Feature | CanMatch | CanActivate |
---|---|---|
When it runs | Before route is matched | After route is matched |
Blocks rendering? | â Yes | â No (route already matched) |
Best for | Access control + performance | Fine-grained access enforcement |
Recommended in v19? | â Yes (especially with Signals) | â Still valid for deeper checks |
đ Final Thoughts
With Angular 19, CanMatch
is no longer just a nice-to-haveâitâs a best practice for dynamic, performant route control. It works perfectly with modern Angular tools like standalone components, Signals, and function-based APIs.
If youâre building secure, modular appsâor just want better performanceâstart integrating CanMatch
into your routing logic.