We will examine Angular's newly released standalone Router APIs. Do they bring real value? What impact can we achieve on the Router's bundle size?
Kevin Kreuzer
@nivekcode
Oct 18, 2022
6 min read
Not long ago, a Tweet by Minko Gechev caught my attention.
Have you noticed the new standalone router APIs?
— Minko Gechev (@mgechev) October 4, 2022
They allow you to use the router without NgModules and are tree-shakable!
You can shave off 11% of the router bundle 🔥https://t.co/3zAVScezUv
Currently in developer preview, stable in v15!
An 11% reduction is impressive! 😎 Let’s put it to the test.
With a fresh brew in hand, I set off to build a simple app featuring two lazy-loaded routes (/movies and /shows) for browsing films and series.
🤫 Pro tip! You can create lazy-loaded feature modules with the use of a simple single command!
| Movies | Shows |
|---|---|
![]() |
Movie and TV show listings in the sample app. (These rankings reflect my personal taste 😉).
So now we end up with a clean application structure: two distinct routes, each backed by its own service providing entries, plus a handful of components that render them. Nothing out of the ordinary.
Now, switch your attention to what really matters here — how large our bundles are.

Initial Bundle size report from the source map explorer
Your application comes in at 246.23 KB, with 203.17 KB residing in the main bundle and 65.62 KB attributed to the router. That translates to 26.6% of the overall app size. While 26.6% might seem significant, it’s worth noting that our app is quite simple, which keeps the total size fairly minimal.
With that baseline established, let’s shift our focus to migrating the application to the router’s standalone APIs.
Standalone APIs
To get the most out of the standalone APIs, we should first review the official docs for a complete understanding of how to integrate them.
A new provideRouter function is available in Angular. It’s designed to supply the application with all necessary Router capabilities, including routes and various router features. In the current setup, these functionalities come through RouterModule.
We now have a clear method for providing router functionalities, but what about the components and directives like router-outlet or routerLink? The solution is straightforward: they can be imported. Every router component and directive is now exposed as a standalone API.
That’s promising — the new APIs cover all our needs. So, what’s the proper way to utilize provideRouter?
The provideRouter function can be supplied as an options argument to the bootstrapApplication function.
const appRoutes: Routes = [];
bootstrapApplication(AppComponent, {
providers: [
provideRouter(
appRoutes,
withDebugTracing(),
withRouterConfig({ paramsInheritanceStrategy: 'always' }),
),
],
});
Hold on — bootstrapApplication? That’s new to me. I’ve never worked with it. In my projects, we call bootstrapModule
via the platformBrowserDynamic function.
Version 14 introduced bootstrapApplication, which lets us bootstrap a standalone component.
So does that imply I must switch to standalone components to benefit from the provideRouter
function?
Correct, at least for the AppComponent. Let’s try out two distinct scenarios.
For the first scenario, we’ll turn our AppComoponent into a standalone component, yet keep using the RouterModule
in our lazy-loaded modules. The second scenario involves converting all components in the app to standalone.
Hybrid approach
To use the provideRouter function, we must make our AppComponent standalone by setting
the standalone property to true.
Because our template relies on router-outlet and routerLink, we also need to add the Standalone APIs RouterOutlet andRouterLinkWithHref to our imports.
import { Component } from '@angular/core';
import { RouterLinkWithHref, RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
imports: [RouterOutlet, RouterLinkWithHref],
standalone: true,
})
export class AppComponent {}
After migrating your AppComponent to a standalone component, both the app.module.ts and theapp.routing.module.ts files become unnecessary and can be removed. The only remaining task is to update your main.ts.
import { enableProdMode } from '@angular/core';
import { provideRouter, Routes } from '@angular/router';
import { bootstrapApplication } from '@angular/platform-browser';
import { environment } from './environments/environment';
import { AppComponent } from './app/app.component';
const routes: Routes = [
{
path: 'shows',
loadChildren: () =>
import('./app/features/shows/shows.module').then((m) => m.ShowsModule),
},
{
path: 'movies',
loadChildren: () =>
import('./app/features/movies/movies.module').then((m) => m.MoviesModule),
},
];
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent, {
providers: provideRouter(routes),
});
Our route definitions were relocated out of app.routing.module.ts and into main.ts; the paths were then updated accordingly. Following that, we supply the array to the provideRouter function within the providers property of bootstrapApplication.
Excellent! A portion of the router's standalone APIs was introduced. Let’s check what the application’s bundle size looks like now.

Bundle size of our application that now uses some of the routers standalone APIs as well as the RouterModule.
The application’s overall bundle now sits at 243.08 KB. What stands out is that while the total size shrank, the router saw a slight increase of 0.13 KB.
The reason is straightforward: we’re pairing provideRouter with RouterModule, which remains in play for our lazy-loaded feature modules.
This setup doesn’t give us the router bundle reduction we’re after. Still, it’s a practical option for those looking to transition incrementally toward fully standalone components.
Full standalone components
Now, let’s take this further. We’ll switch our lazy-loaded routing modules to lazy-loaded standalone components.
First, we’ll delete movies.routing.module.ts and movies.module.ts. Then, we’ll refactor movies.component.ts into a standalone component.
import { Component } from '@angular/core';
import { NgFor } from '@angular/common';
import { MoviesService } from './movies.service';
import { MovieCardComponent } from './movie-card/movie-card.component';
@Component({
selector: 'app-movies',
templateUrl: './movies.component.html',
styleUrls: ['./movies.component.scss'],
standalone: true,
imports: [MovieCardComponent, NgFor],
})
export class MoviesComponent {
movies = this.moviesService.getMovies();
constructor(private moviesService: MoviesService) {}
}
In the component's decorator, we assign true to the standalone setting and include an imports array holding both MovieCardComponent and NgFor.
Note: I have already taken care of converting
MovieCardComponentinto a standalone component beforehand.
Naturally, the shows route requires an identical procedure. However, I suspect you'd rather not see me repeat those details yet again.
With our features now acting as standalone components, we must return to main.ts and modify the routes, swapping out loadChildren for the loadComponent function.
const routes: Routes = [
{
path: 'shows',
loadComponent: () =>
import('./app/features/shows/shows.component').then(
(c) => c.ShowsComponent,
),
},
{
path: 'movies',
loadComponent: () =>
import('./app/features/movies/movies.component').then(
(c) => c.MoviesComponent,
),
},
];
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent, {
providers: [provideRouter(routes)],
});
Given its name, loadComponent makes it possible to defer loading a standalone component, bypassing the need for a module altogether.
This is great news! We've fully migrated the application to use standalone components. What's more, we've eliminated theRouterModule dependency, replacing it solely with the router's standalone APIs.
Now, let's rebuild the application and take a closer look at the generated bundle.

Bundle size after converting our app to standalone components and standalone router APIs
At this point, the total bundle size sits at 233.61 KB, which represents a 12.62 KB reduction while delivering the exact same functionality. That's certainly impressive.🤩 But since our focus is on the router, let’s zoom in there.
Currently, the router itself comes in at 60.54 KB, marking a 5.08 KB drop—that’s a 7.74% improvement. This aligns perfectly with what I observed in my simplified setup using source-map-explorer. I can easily see more complex projects, especially those measured with different tools, reaching the 11% gain that Minko reported.
Summary
The standalone router APIs are truly impressive. They let us build the same rich functionality while keeping the final bundle leaner.
However, keep in mind these APIs are still in developer preview and won’t be stable until v15. Because of that, I’d hold off on using them in production today. Also, adopting them requires your entire app to rely on standalone components.
If your application is large, a step-by-step migration could be a sensible approach toward the new standalone Router APIs. Still, remember that mixing provideRouter with RouterModule is fine as a temporary measure, but it shouldn’t be the final state.
Do you enjoy the theme of the code preview? Explore our brand new theme plugin
Skol - the ultimate IDE theme
Bring the aurora experience right into your code editor. A clean yet striking dark theme that is easy on the eyes and visually appealing.
Craft more intelligent interfaces with Angular + AI
Angular + AI Video Course
A practical workshop that demonstrates how to bring AI into Angular applications, leveraging Hash Brown for responsive, intelligent interfaces.
Explore real-time streaming chat, tool-assisted interactions, generative UI patterns, and well-defined output schemas, all through guided examples.
Get ready for what’s next in Angular and turn yourself into a Signals pro!
Angular Signals Masterclass eBook
Find out why Angular Signals have become a necessity, examine the full range of their interactive methods, and dive into the mechanics that power them.
Sharpen your coding expertise and get poised for what lies ahead in Angular. Stay ahead of the curve!
Enjoying this content and eager to conquer Angular's latest Signal Forms?
Angular Signal Forms: A Comprehensive Practical Workshop
Get to grips with Angular's recently introduced Signal-Forms across a dozen step-by-step sections that blend concepts with practical exercises.
Dive into form fundamentals, validation rules, bespoke controls, nested forms, transitioning approaches, and much else besides.
Never miss a post
from our blog
Subscribe to the Angular Experts Content Updates & News and we will let you know the moment a new article on Angular, Ngrx, RxJs, or other exciting Frontend topics goes live.
Your email stays private, and you are free to unsubscribe whenever you like!
Questions & feedback
Feel free to ask questions and share your insights and personal experiences on the subject
You might also like
Take a look at these additional Angular Experts articles to deepen your understanding of related areas such as Angular !

Top 10 Angular Architecture Mistakes You Really Want To Avoid
In 2024, Angular keeps changing for better with ever increasing pace, but the big picture remains the same which makes architecture know-how timeless and well worth your time!

Tomas Trajan
@tomastrajan
Sep 10, 2024
15 min read

Angular Signal Inputs
Revolutionize Your Angular Components with the brand new Reactive Signal Inputs.

Kevin Kreuzer
@nivekcode
Jan 24, 2024
6 min read

Improving DX with new Angular @Input Value Transform
Embrace the Future: Moving Beyond Getters and Setters! Learn how to leverage the power of custom transformers or the build in booleanAttribute and numberAttribute transformers.

Kevin Kreuzer
@nivekcode
Nov 18, 2023
3 min read
Leverage our deep know-how to boost your team
From big corporations to early-stage startups, our consulting, workshops, and open-source contributions have supported a wide range of projects. We’re proud of our front-end expertise and excited to help drive your success


