Lazy‑Loading Ionic Pages with Ionic Router to Cut Startup Bundle Size
Learn how to defer loading of rarely‑used pages in an Ionic Angular app, reduce the initial download, and verify the impact with Chrome DevTools.
11 Jul 2026, 09:37 UTC

Problem: Slow first paint on low‑end devices
When you start a fresh Ionic Angular project, the router loads every page module eagerly. All components, templates, and styles are bundled into a single main.js file. On a typical starter, this bundle can exceed 2 MB gzipped, causing noticeable delays before the user sees anything on the screen, especially on slower networks or older phones.
Thesis: Lazy‑load infrequently used pages to shrink the initial bundle
By configuring the Ionic Router to load a page only when the user navigates to it, the main bundle contains only the code needed for the initial view. The lazy‑loaded page is split into a separate chunk that is fetched on demand. This reduces first‑paint time and keeps navigation simple because the router API stays the same.
How lazy loading works with Ionic Router
Ionic Router is a thin wrapper around Angular’s Router. Lazy loading relies on Angular’s loadChildren syntax, which tells the router to import a module dynamically. The module must be declared in its own file and should not provide services that need to be singletons across the app unless they are marked providedIn: 'root'.
Key concepts
- Lazy chunk: A separate JavaScript file generated by the build tool that contains the lazy‑loaded module.
- loadChildren: A function returning a promise that imports the module.
- providedIn: 'root': Makes a service a singleton at the application level, avoiding duplicate instances in each lazy module.
Worked example: Lazy‑loading the Profile tab in a tab‑based starter
We’ll start from the default Ionic Angular tabs template and convert the Profile tab to lazy load.
1. Create a baseline project
# Run in a terminal, no special permissions needed
ionic start demo tabs --type=angular
cd demo
ionic serve # verify the app loads; keep this running for later comparison
Open Chrome DevTools → Network, disable cache, and reload. Note the size of the main chunk (e.g., main.js ≈ 1.8 MB gzipped).
2. Generate the Profile page as a standalone module
ionic generate page profile # This creates src/app/profile/profile.module.ts, etc.Edit
src/app/profile/profile.module.tsto ensure it does not provide any service that must be a singleton. If you have a service likeDataService, addprovidedIn: 'root'in its injectable decorator instead of listing it in the module’sprovidersarray.3. Update the tabs router to lazy load Profile
Open
src/app/tabs/tabs.router.ts. Find the route for the Profile tab and replace the component reference with aloadChildrenfunction:{ path: 'profile', loadChildren: () => import('../profile/profile.module').then(m => m.ProfileModule), }Remove the old
component: ProfilePageline.4. Rebuild and verify the split
ionic serve # restart the dev server to pick up the new route configAgain, open DevTools → Network, disable cache, reload. You should see two chunks:
main.js(now smaller, e.g., 1.2 MB)profile-profile-module.js(the lazy chunk, loaded only when navigating to Profile)
Trade‑offs and limitations
Lazy loading improves startup but introduces a small navigation latency the first time a lazy page is accessed, because the browser must fetch the extra chunk. On a typical 3G connection this may add 100‑300 ms. Subsequent visits are fast because the chunk is cached.
Another consideration is service provisioning. If you accidentally provide a service inside a lazy module’s providers array, each lazy load gets its own instance, breaking singleton expectations. The safe pattern is to keep such services in the root injector (providedIn: 'root') or provide them in a shared module that is imported by the root module only.
Practical verification steps
- Measure initial bundle size before and after the change (DevTools → Network → Disable cache → Reload).
- Record the time to first paint (Performance tab → Timings).
- Navigate to the Profile tab and watch the Network tab for the lazy chunk request; note the request duration.
- Navigate away and back to Profile; the lazy chunk should load from (disk) cache, showing a much shorter duration.
If the lazy chunk does not appear, double‑check the loadChildren path and ensure the module is exported correctly.
Actionable closing
Start by auditing your route map: identify pages that are visited infrequently (settings, help, infrequent tabs). Convert those to lazy load using the steps above. After each change, verify bundle size reduction with DevTools and confirm that the first‑time navigation delay remains acceptable for your target devices. This incremental approach yields measurable startup improvements without sacrificing the simplicity of the Ionic Router API.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.