Route Guards
Route guards are functions that the Angular Router runs at specific points in the navigation lifecycle to decide whether a navigation should proceed, be redirected, or be blocked entirely. Common use cases include restricting access to authenticated users only (canActivate), confirming that a user really wants to leave a page with unsaved form changes (canDeactivate), and pre-loading data before a component even renders (resolve). Since Angular 14+, guards are written as plain functions (functional guards) rather than injectable classes implementing interfaces like CanActivate, which reduces boilerplate significantly and is now the recommended style for Angular 17+ applications.
Cricket analogy: canActivate is like a stadium turnstile checking a valid ticket before letting a fan in, canDeactivate is like security confirming you really want to leave during a super over, and resolve is like fetching the pitch report before you take your seat.
canActivate — Protecting Routes
A canActivate guard runs before a route is activated and determines whether navigation is allowed to proceed. It can return a boolean, a UrlTree (to redirect elsewhere), or an Observable/Promise resolving to either, which lets you perform asynchronous checks like verifying a session token with a backend. Functional guards use the inject() function to access services, since they run outside a component's constructor context.
Cricket analogy: A canActivate guard is like the third umpire reviewing a run-out before confirming the decision stands, returning either 'not out' (allow), a redirect to the replay room (UrlTree), or waiting on a slow-motion feed (Observable) using inject() to pull in the review system.
// auth.guard.ts
import { inject } from '@angular/core';
import { Router, type CanActivateFn } from '@angular/router';
import { AuthService } from './auth.service';
export const authGuard: CanActivateFn = (route, state) => {
const auth = inject(AuthService);
const router = inject(Router);
if (auth.isLoggedIn()) {
return true;
}
// Redirect to login, preserving the attempted URL for a post-login redirect
return router.createUrlTree(['/login'], {
queryParams: { returnUrl: state.url },
});
};
// app.routes.ts
export const routes: Routes = [
{ path: 'dashboard', component: DashboardComponent, canActivate: [authGuard] },
];canDeactivate and Other Guard Types
canDeactivate runs when navigating away from a route and is commonly used to warn users about unsaved changes, typically by prompting a confirm dialog before allowing the navigation to continue. canMatch (which superseded the older canLoad) determines whether a route definition is even considered a match candidate at all — useful for feature-flagging entire route branches or choosing between two components for the same path based on a condition. A resolve function isn't strictly a guard but runs alongside guards to fetch data before the route activates, so the component never renders in a 'loading' state for that data.
Cricket analogy: canDeactivate is like an umpire confirming you really want to retire hurt with an unresolved review pending, canMatch is like a franchise choosing between two overseas players for the same slot based on visa eligibility, and resolve pre-fetches the pitch report first.
import type { CanDeactivateFn } from '@angular/router';
import type { EditFormComponent } from './edit-form.component';
export const unsavedChangesGuard: CanDeactivateFn<EditFormComponent> = (component) => {
if (component.hasUnsavedChanges()) {
return confirm('You have unsaved changes. Leave anyway?');
}
return true;
};Because functional guards are plain functions, they compose naturally with utilities like Angular's own combineGuards-style patterns or simple helper functions — you can write a reusable hasRoleGuard(role: string) factory that returns a CanActivateFn, something that was much more awkward with class-based guards.
Route guards are a UX and routing convenience, not a security boundary. A canActivate guard only prevents the Angular Router from rendering a component in the browser — the actual protected data must still be secured server-side (e.g. via authenticated API endpoints), since a determined user can call the backend directly, bypassing the frontend guard entirely.
- Since Angular 14+, guards are written as plain functions (
CanActivateFn,CanDeactivateFn, etc.) usinginject(), not injectable classes. canActivatedecides whether a route may be entered; returning aUrlTreeperforms a redirect.canDeactivateruns on navigating away, commonly used for unsaved-changes confirmation prompts.canMatchdecides whether a route definition is even a candidate match, useful for feature flags.resolvepre-fetches data before route activation so the component mounts with data already available.- Guards are a client-side UX mechanism, not a substitute for server-side authorization checks.
Practice what you learned
1. What is the recommended way to write route guards in Angular 17+?
2. What does returning a `UrlTree` from a `canActivate` guard accomplish?
3. Which guard type is most appropriate for warning a user about unsaved form changes before leaving a page?
4. What is the primary purpose of a route `resolve` function?
5. Why are route guards considered insufficient as a sole security measure?
Was this page helpful?
You May Also Like
Angular Router Basics
Learn how Angular's built-in router maps URL paths to components, enabling single-page applications to feel like multi-page sites without full page reloads.
Lazy Loading Feature Routes
Discover how to split an Angular application into smaller JavaScript bundles that load on demand as users navigate, dramatically improving initial load performance.
The inject() Function
Learn how the inject() function offers a flexible alternative to constructor injection, and how it enables DI in functional contexts like guards, resolvers, and interceptors.
Creating and Injecting Services
Learn how to define an Angular service class, register it with Angular's dependency injection system, and inject it into components and other services.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics