Table of Contents
ToggleIntroduction – Angular v16 to Angular v20 (with Ionic and Capacitor)
I’m currently managing this Bail Bonds app using Capacitor that is written using the Ionic Angular framework. Recently, I finished reading Modern Angular by Armen Vardanyan, and I wanted to write something as I update the app with the strategies and techniques used in this book. Some of the Angular 19 features that are discussed in the book include standalone modules, dependency injection, changes to building blocks such as inputs, directives, and type-safe forms; and last but not least, signals.
In this guide however, I’ll first be showing you an example of how to take this Capacitor Ionic Angular App from version 16 to version 20. Later on through other guides, I’ll be demonstrating the use of the new features that Angular 20 includes.
So let me begin by telling you about the current purpose and architecture of the app. The app is a simple, informative way for BillBailBonds.com’s clients to get information for payment, forms, office location, and to share the app with their contacts. The app serves as a facilitator for Bill’s associates and customers, allowing them to quickly navigate to links and share Bill’s services. Google Play Store has published the BillBailBonds.com app, however the App Store has deemed the app as lacking functionality. I’ll be adding the solution to that in another guide as well by extending the app’s functionality.
There is nothing special about the app’s architecture. There’s an App Module, which declares components and imports some other modules, including the AppRoutingModule. I will be changing the architecture of the app later on after we make use of the new features released after Angular 17.
How does Upgrading Angular Versions work?
Before the upgrade, if I run ng version
, I’ll get the following output:

Now we can run ng update
and see what the recommended steps to update Angular are.
If you’ve ever updated your Angular projects’ major version before, you will notice that they occur in gradual updates. In other words, some packages you cannot update from the current version to the latest. For example, to get from @angular/cli 16.2.16 to @angular/cli 20.0.0, you make gradual upgrades going to @angular/cli 17.3.9 first, then moving your way up to until you make it to version 20. This is because some Angular packages provide different migration schematics to go from major version to the next version.
These schematics describe changes and how to handle them in your codebase. Some of these changes might need manual action, while others are handled by the migration schematics themselves. We’ll see some of these manual changes that require developer interaction in this guide and some that are automated as well. Here’s a screenshot of what Google says about this in a Google AI response.

Upgrading from Angular 16 to Angular 20
To upgrade, simply run the commands listed in the “Command to update” column of the output you receive after running ng update
.

You will notice that in this case, ng update @angular-eslint/schematics
is one of those packages that can update while skipping major versions. As you see here we can go from @angular-eslint/schematics 16.3.1
to @angular-eslint/schematics 20.1.1
by running ng update @angular-eslint/schematic
. After running this however, in the current project I have set up, I get the error:
Migration failed: Incompatible peer dependencies found.
Peer dependency warnings when installing dependencies means that those dependencies might not work correctly together.
You can use the '--force' option to ignore incompatible peer dependencies and instead address these warnings later.
See "/private/var/folders/65/46cgdqy16z97123j5yt64pfh0000gn/T/ng-X6H5nx/angular-errors.log" for further details.
So let’s run it using the --force
flag. This is a common tactic that you will use while upgrading many Angular packages from time to time, as you will be able to upgrade the missing peer dependencies later. Also, some of the upgrades we’ll be forcing could potentially solve issues for some of the packages.

After running the recommended commands with the --force
flag, you will now see the installation updated and that it performed the gradual updates from major version to major version automatically for us.
You will also see the automated migrations that angular implements in its migration schematics:

Now run ng update
again to see what the next steps are.

Great, now we have to update @angular/cli and @angular/core to the next major versions, v17.
You will have to commit your current changes if you’re in a Git Repo before continuing the updates.
Keep running the ng update
command plus the recommended command in the Command to update
column you see in the output. Use the --force
flag if necessary until you get to the latest cli and core versions.
We are also migrating the project to the new build system. https://angular.dev/tools/cli/build-system-migration
After many updates and migrations, we finally, we made it to version 20.
Fixing errors after Upgrading to Angular 20
Now let’s see what happens when we try to run ng serve
.
Issues with Vite and the new Angular Build System
The only issue I see is a warning regarding “The above dynamic import cannot be analyzed by Vite.”

A lot of changes have transpired from Angular 16 but the app should still run regardless since we still have the same setup and NgModules haven’t been deprecated yet.
So let’s solve this first because we wouldn’t want our app to be useless after updating to Angular 20. The problem we are facing in this particular app is that we have to update to the latest Ionic Angular package. I noticed this after also noticing that the builder was set up for SSR and that the serve
command was using the a previous version of the builder. Although the angular-devkit package has not been deprecated yet, I decided to update the app to use the new @angular/builder as well.
As of Angular 17 and later, the new build system uses the application
builder. The application
builder also includes SSR builds now, so we can use this instead of having to use the SSR builder. Neat.
There’s an automated migration that exists to upgrade your application to use the new builder:
ng update @angular/cli --name use-application-builder
That performs a couple of changes that you can read about here.


You will be able to run ng serve
with the new builder now. Note that the serve
builder is now @angular/build:dev-server
and the builder for build is now set to @angular/build:application
Installing the Required Ionic Angular 8.0 Version
Since this app uses Ionic Angular, we’ll also want to update to the latest Ionic Angular Package. You can follow this guide on updating to the Ionic Angular 8.0 in order to achieve the upgrade.
After making those changes, we can see the app now is functional again and also using Angular 20!
Installing the skipped peer dependencies when we used the force
flag
You should also note that every time you run npm i
now, you will get an error because you used the --force
flag. You can install the peer deps now as necessary.
How to read the required peer deps.

As you can see in this image, the current angular-fontawesome version is asking for @angular/core@^16.0.0, that is in the range of anywhere as long as it’s in the Major release of 16.
So, in order to fix this, since we’re in the latest Angular version, simply update to the latest angular-fontawesome version. I prefer to uninstall the current version of the package by running
npm uninstall @fortawesome/angular-fontawesome --force
and then re-installing the latest version by running
npm install @fortawesome/angular-fontawesome
you might have to use the --force
flag if you’re still behind in other peer deps.
Anyhow, continue the process until all the peer dependencies have been resolved correctly.
I will be creating additional content as to the other app updates available such as standalone, dependency injection, signals, and building blocks in separate posts. That way, the content will be neatly separated and I don’t have to write one big blob. For now, I hope you have understood how simple it is to take your app from Angular 16 to Angular 20 by using the –force flag and the ng update
command. By reading this blog, you should have briefly understood the new build system which incorporates SSR and Vite into the @angular/builder
package. Lastly, you should also have noted that in order for your Ionic Angular app to work with Angular 20, you should also have updated to Ionic 8.
