← All articles

Migrating Ionic Angular to Standalone Automatically with Codemods

How to run @ionic/angular-standalone-codemods with Prettier prep, what each migration step changes, and what to verify before committing.

Published
Migrating Ionic Angular to Standalone Automatically with Codemods cover image

This article explains how to migrate Ionic Angular to Standalone automatically using the official @ionic/angular-standalone-codemods. For background on Ionic Angular Standalone, see the article below.

https://zenn.dev/rdlabo/articles/8beb8c91e7d337https://zenn.dev/rdlabo/articles/8beb8c91e7d337

@ionic/angular-standalone-codemods uses ts-morph for code transformation. Every transformed file passes through ts-morph, which can change line breaks and indentation beyond the migration itself, producing large diffs. I recommend running a formatter first so you only see meaningful changes. Here is one example.

% npm install -D prettier
% npx prettier --parser typescript --write "./src/**/*.ts" &&  prettier --parser angular --write "./src/**/*.html"

If you already use Prettier, skip this step.

What is @ionic/angular-standalone-codemods?

@ionic/angular-standalone-codemods is Ionic's official codemod for migrating Ionic Angular to Standalone. Like Angular CLI's ng update, it automatically applies the code changes needed for Standalone.

https://github.com/ionic-team/ionic-angular-standalone-codemodshttps://github.com/ionic-team/ionic-angular-standalone-codemods

Running it is simpleβ€” from your Ionic Angular project root:

% npx @ionic/angular-standalone-codemods

A prompt appears. First you see:

β–²  ⚠️  This utility is experimental. Always review the changes made before committing them to your project. ⚠️
β”‚
β–²  For manual migration, see the guide at: https://www.ionicframework.com/docs/angular/build-options#migrating-from-modules-to-standalone

Just a confirmation. The tool creates large diffs, so commit your current work before running it. Next:

β—†  Would you like to run this migration as a dry run? No changes will be written to your project.
β”‚  ● Yes / β—‹ No
β””

This asks whether to apply changes or preview only (dry run). Choose Yes to preview. Choose No to run the migration for real.

β—†  Please enter the path to your project (default is the current working directory):
β”‚  /Users/sakakibara/dev/winecode/app_

Finally it confirms the project path. The default is the current directory, but you can specify another path. Press Enter to run. It finishes in seconds with:

β—‡  Project migration at /Users/sakakibara/dev/winecode/app completed successfully.
β”‚
β—†  We recommend reviewing the changes made by this migration and formatting your code (e.g., with Prettier) before committing.

The Standalone migration codemod is done. I recommend formatting again with Prettier and reviewing the Git diff.

% npx prettier --parser typescript --write "./src/**/*.ts" &&  prettier --parser angular --write "./src/**/*.html"

What changes are applied

0001-migrate-app-module

The first change replaces IonicModule.forRoot in the root NgModule with provideIonicAngular. This is for apps that have not yet moved Angular itself to Standalone.

       import { NgModule } from '@angular/core';
-      import { IonicModule } from '@ionic/angular';
-
+      import { provideIonicAngular } from '@ionic/angular/standalone';
+  
       @NgModule({
-        imports: [IonicModule.forRoot({ mode: 'md' })]
+        imports: [],
+        providers: [provideIonicAngular({ mode: 'md' })]
       })
-      export class AppModule {}
+      export class AppModule { }

0002-import-standalone-componen

The second change imports Ionic Standalone components directly, because IonicModule is no longer used.

        import { Component } from "@angular/core";
+       import { IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonItem, IonLabel } from "@ionic/angular/standalone";

        @Component({
          selector: 'my-component',
...
               </ion-list>
             </ion-content>
           \`,
-          standalone: true
-        }) 
+          standalone: true,
+          imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonItem, IonLabel]
+        })
         export class MyComponent { }

IonIcon also changed: instead of referencing files under assets, it uses icons registered with addIcons.

         import { Component } from "@angular/core";
+        import { addIcons } from "ionicons";
+        import { logoIonic } from "ionicons/icons";
+        import { IonIcon } from "@ionic/angular/standalone";
 
         @Component({
           selector: 'my-component',
           template: '<ion-icon name="logo-ionic"></ion-icon>',
-          standalone: true
-        }) 
-        export class MyComponent { }
+          standalone: true,
+          imports: [IonIcon]
+        })
+        export class MyComponent {
+          constructor() {
+            addIcons({ logoIonic });
+          }
+        }

Icons not registered with addIcons will not display. However, if they were registered elsewhere (stored on the window objectβ€” in main.ts, another component, or a service), they can still appear. Registering in the component itself keeps the total bundle smallest.

0003-migrate-bootstrap-application / 0006-migrate-angular-app-config

The third change replaces IonicModule.forRoot loaded via importProvidersFrom in bootstrapApplication with provideIonicAngular. This is for apps already on Angular Standalone.

-    import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
+    import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
...
     bootstrapApplication(AppComponent, {
       providers: [
         { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
-        importProvidersFrom(IonicModule.forRoot({ mode: 'ios' })),
         provideRouter(routes),
+        provideIonicAngular({ mode: 'ios' })
       ],
     });

0004-migrate-import-statements

The fourth change moves every import from @ionic/angular to @ionic/angular/standalone. After migration, imports from @ionic/angular are not usable. Without loading the module, that is expected.

       import { Injectable } from '@angular/core';
-      import { ModalController } from '@ionic/angular';
+      import { ModalController } from '@ionic/angular/standalone';
 
       @Injectable()
       export class MyService {

0005-migrate-angular-json-assets

The fifth change removes copying node_modules/ionicons/dist/ionicons/svg in angular.json. In Ionic Angular Standalone, IonIcon bundles through addIcons, so the assets entry is no longer needed.

           architect: {
             build: {
               options: {
-                assets: [
-                  "src/favicon.ico",
-                  "src/assets",
-                  {
-                    glob: "**/*.svg",
-                    input: "node_modules/ionicons/dist/ionicons/svg",
-                    output: "./svg",
-                  },
-                ],
+                assets: ["src/favicon.ico", "src/assets"],
               },
             },
           },

Summary

Inspired by ng update, the Ionic team ships migration tools for major changes (including Capacitor major releases). These tools make Ionic upgrades easier. Give them a try.