🔐 Angular 19: Smarter Route Protection with CanMatch

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

FeatureCanMatchCanActivate
When it runsBefore route is matchedAfter route is matched
Blocks rendering?✅ Yes❌ No (route already matched)
Best forAccess control + performanceFine-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.

Leave a Comment

Your email address will not be published. Required fields are marked *