Upgrading Angular in a complex application is more than just updating to a new version; it’s a strategic decision that impacts nearly every part of your codebase. This case study details how we successfully managed a multi-version upgrade for a modular B2B healthcare platform.
This behind-the-scenes look highlights our planning, execution, and stabilization processes during a major migration, all while maintaining development and ensuring product stability. If you’re considering a similar upgrade or determining whether now is the right time, we hope this case study provides the insights needed to make informed and confident decisions.
Project and industry overview
We upgraded a B2B web platform in the healthcare industry, which connects hospitals and clinics with equipment manufacturers.
When we started the upgrade in 2023, the project was running on Angular 14, a version that was no longer officially supported. We aimed to upgrade to Angular 17, the latest stable version at the time, to ensure long-term stability and access to new features such as Signals, the Standalone API, and the new control flow syntax.
The frontend was maintained by a team of four frontend developers and two full-stack engineers, working together on a large, modular codebase. Since new features were being developed in parallel, we needed an upgrade plan that was predictable, low-risk, and allowed for gradual testing and rollout.
Thanks to this approach, we could later upgrade to Angular 19 with minimal friction, confirming that the effort invested in this migration continues to pay off.
Reason for the Angular version upgrade
Upgrading to Angular 17 was a strategic step toward building a faster, more stable, future-ready product. We were reaching the limits of what Angular 14 could support, and staying on an outdated stack would have only slowed us down.
From a business perspective, the benefits were clear: faster feature delivery, shorter development cycles, fewer regressions, and a smoother experience for our team. For the product itself, this upgrade resulted in improved performance, more effortless scalability, and a stronger foundation for future development. It enabled faster feature delivery, simpler team onboarding, and made future upgrades significantly less challenging.
Under the hood, these outcomes were made possible by key improvements introduced in recent Angular 15-17 versions:
- Signals (Angular 16): brought more predictable, performant reactivity, especially useful in complex application parts.
- Standalone API (stable since Angular 15): helped us clean up module structure and reduce boilerplate,
- New control flow syntax (Angular 17): made our templates leaner and easier to reason about,
- Performance boost: faster build times with esbuild, and official SSR support gave us more options for improving app speed.
📘 If you want to learn more about Angular 14-20 changes that improve efficiency, UX, DX, and app performance, download our free ebook “The Ultimate Guide to Angular Evolution”.
Challenges
While the upgrade to Angular 17 ultimately delivered strong results, the path wasn’t without friction. As with large-scale migration, we must tackle several technical and organizational challenges.
Current project state
At the time of the upgrade, the project ran on Angular 14 with Angular Material powering the UI. The application itself was extensive and modular, spanning multiple business domains, meaning that even small changes could ripple through the system unexpectedly.
Architecture and technologies in use
The architecture added its layer of complexity. We used Nx for monorepo management, NgRx for state handling, Storybook for component development, and a custom design system built on Angular Material. It was a powerful stack, but also one that demanded caution. Every major update had to be cross-checked for compatibility across dozens of components and services.
Problems faced during the update
One of the main challenges was the complexity of the project itself. Each change had to be carefully verified with multiple business domains and modules to prevent regressions.
A significant effort was also required to update Angular Material to the new MDC-based components introduced in version 15. Because our UI had been heavily customized, we couldn’t rely on automatic migrations. We decided to postpone this step until after the Angular 15 upgrade to reduce risk, and then migrated the Material components gradually, to maintain stability and avoid disrupting ongoing work.
We had to resolve several issues related to third-party dependencies. Some libraries hadn’t yet caught up with the latest Angular versions, forcing us to either update them manually, patch them, or, in some cases, adapt our code to deal with breaking changes. This part of the process required extra attention and extensive testing to ensure nothing broke.
Upgrade Process
Because the migration spanned several major versions (from Angular 14 to 17), we knew from the beginning that trying to do it all at once would be too risky. Instead, we planned an incremental upgrade, version by version, to isolate potential issues, simplify debugging, and keep the process manageable.
Planning and preparations for the update
Angular changelog and dependencies audit
Before starting the upgrade, we carefully reviewed the changelog and breaking changes introduced in each Angular version from 15 to 17. We also checked the compatibility of third-party dependencies to ensure they would work with the target versions or identify where updates or adjustments were needed.
Start time and resource management.
Timing was just as important as planning. Since multiple developers were working on the project, we had to coordinate the timing of the upgrade around other ongoing work. We picked a sprint where the frontend was slightly ahead of the backend, and no major or critical features were in active development. It allowed us to isolate the upgrade without disrupting the broader roadmap, and other developers could continue working on smaller features in parallel.
While a single developer could have handled the task, we assigned two people to the job to speed up the process of spotting regressions and fixing any build issues, visual bugs, or failing unit tests.
———————————-
Related: Planning an Angular Upgrade: Key Steps & Risk Management
———————————–
- Identifying outdated or heavily customized libraries
A big part of the preparation involved dealing with Angular Material’s transition to MDC components, which was the most complex aspect of the upgrade. We planned to first migrate the app to Angular 15 while keeping the legacy Material components
- Upgrade version by version
We intentionally decided not to upgrade all versions at once. After each major version bump, we tested thoroughly and monitored for regressions. It allowed us to isolate and debug potential issues more effectively, making the overall process more predictable and stable.
Tools used for the migration
We relied on a mix of official tools and Nx-specific utilities to support the upgrade. The Angular Update Guide helped outline each version’s breaking changes, deprecations, and recommended steps.
Since our project was built with Nx, we also used the nx migrate command, which streamlined updating dependencies, generating migrations, and applying changes in a controlled way.
Step-by-step process of upgrading
Our upgrade journey began with the transition to Angular 15. After an initial analysis of the project’s dependencies and architecture, we used Nx migrations to run the upgrade process. Nx handles most of the heavy lifting, such as updating Angular core packages and NgRx packages, and adjusting configuration files and code where necessary.
The typical upgrade flow includes (with steps 3 and 4 handled by Nx in our case):
- Updating node.js to a version needed for the target Angular release, if required,
- Updating Nx to the latest compatible version to ensure tooling compatibility and to take advantage of migration utilities,
- Updating Angular core packages (@angular/core, @angular/cli, etc.),
- Updating NgRx packages to match the updated Angular version,
- Upgrading all third-party dependencies to the latest versions compatible with the new Angular version,
- Fixing build-time issues, if any arose due to breaking changes or outdated configurations,
- Running linters and tests to verify code quality and ensure nothing broke during the upgrade,
- Launching Storybook and the application itself to perform visual and regression testing.
After completing these steps, we double-checked all package versions to ensure we used the most recent stable releases. We also cross-referenced the steps with the official Angular Update Guide to confirm that no critical steps were skipped or overlooked during the automated migration.
It’s highly recommended to split each of these phases into separate commits. It makes tracking changes, debugging regressions, and isolating specific upgrade steps easier. Nx migrations can assist significantly here, as they can organize changes in a commit-friendly way.
Angular Material Update
Once on version 15, we focused on migrating our UI layer to use the new MDC-based Angular Material components. This transition was the most complex part of the process – an experience likely shared by many teams working with moderately outdated codebases that depend heavily on Angular Material.
We took a step-by-step approach to manage the complexity: migrating one Material component at a time. Some components needed minimal or no changes, allowing us to integrate those updates seamlessly into our regular sprint cycles as small, low-risk tasks. This strategy made isolating and verifying each change easy, reducing the chances of regressions and helping us quickly spot any visual or behavioral differences in the UI.
Since each update was self-contained, code reviews and debugging remained straightforward. This approach also allowed us to continue developing new features simultaneously without compromising stability. It was a key factor in helping us modernize our UI with minimal disruption to the broader development workflow.
Once the MDC component migration was complete, we resumed the Angular upgrade process – moving to version 16, then to 17 – by applying the same version-by-version approach that had already proven effective earlier in the process.
Keep new features separate from version upgrades
While it can be tempting to introduce new Angular features during an upgrade, it’s crucial to treat feature adoption as a separate task. Most Angular features are supported across several recent versions, so there’s usually no rush to migrate from them immediately.
Combining new feature work with a version upgrade can dramatically increase the number of changed files, making it harder to distinguish between what was necessary for the upgrade versus what’s part of a feature enhancement. Keeping the scope focused on updating simplifies code review, improves traceability, and ensures stability. Once the version upgrade is complete and tested, adopting new features can be done more deliberately and cleanly in follow-up tasks.
To introduce new Angular features without disrupting ongoing development, we adopted an incremental migration strategy. Rather than pausing feature work, we modernized the codebase opportunistically: whenever a task required us to touch a component, we evaluated whether it made sense to migrate it to newer Angular patterns like standalone components, the new control flow syntax or Signals-based inputs, outputs and queries – as long as the changes wouldn’t introduce too much noise to the actual feature work.
In quieter periods or between larger feature tasks, we also carved out time for dedicated migration tasks, sometimes targeting an entire application module in one go. Angular’s built-in schematics played a key role here, making it easier to adopt modern APIs without slowing down development. This blended approach allowed us to evolve the codebase while steadily maintaining momentum on new features.
How long does Angular Upgrade take?
The first set of updates, from Angular 14 to 15, wasn’t particularly complicated in itself. Most of the time was spent on regression testing, ensuring everything was functioning as expected after each version update. For more complex applications, this upgrade can typically take up to a few days, depending on the size of the codebase and the number of dependencies involved. However, the process’s most time-consuming part was the update of Angular Material components to the MDC version. It required careful migration due to customizations and the scale of the UI.
Once the Material components were updated and stable, the subsequent Angular 16 and 17 upgrades were much quicker. This step-by-step approach helped us avoid major setbacks and track regressions with precision, ensuring the application’s stability.
There are many factors that can influence how long an Angular upgrade takes. We explored them in detail in our article “How Long Does an Angular Upgrade Take — and How to Keep Feature Delivery on Track.”
If you’re considering an upgrade but unsure how much time and effort it might require in your specific case, fill out our short survey, and we’ll prepare a personalized report to help you plan with confidence.
Results
After the upgrade, we could modernize the application without disrupting ongoing development. In this section, we’ll break down the technical and business outcomes of the migration, along with the benefits it brought and how long the entire process took.
Technical and business benefits
From a technical perspective, the upgrade brought the project up to Angular 17 with a clean and modern codebase that’s now easier to maintain and extend. This update also laid the groundwork for introducing new features and capabilities, more efficiently moving forward. In our case, we adopted standalone components, Signals, and the new control flow at a later stage, which simplified development and boosted performance.
On the business side, the upgrade improved long-term maintainability and reduced technical debt. Development velocity has increased with better performance, faster build times (thanks to esbuild), and modern tooling. Having an up-to-date, stable tech stack also gives us more confidence in delivering new features faster and onboarding developers more easily. In the long run, this modernization helps reduce maintenance costs and minimizes the risks of unexpected issues caused by outdated dependencies.
Lessons learned from the process
One of the key takeaways was that planning and preparation make a huge difference, especially when upgrading across multiple major versions. We avoided most surprises by breaking the process into smaller steps, verifying third-party compatibility early, and aligning the timing with the team’s development cycle.
We also learned that updating complex elements like Angular Material is best handled gradually and early. Migrating to MDC components separately helped us avoid merging two significant sources of change at once.
Lastly, leaving time between major upgrades allowed us to catch regressions better and maintain stability, rather than rushing through the upgrade and dealing with a flood of regressions after the fact.
Practical advice for future upgrades
Don’t stop after the initial upgrade – this may be a great starting point. Once we upgraded the application to Angular 17, subsequent updates became much quicker and smoother. We were able to update to newer versions shortly after their release, minimizing any delays and keeping the project up-to-date with the latest features.
A few key pieces of advice for a successful upgrade:
- Plan well: take the time to understand the scope of the changes and prepare for potential obstacles before starting the upgrade.
- Split the update into smaller steps: break the upgrade process into smaller parts so you can easily track changes and debug what has been modified in each step.
- Separate new features from the update: avoid combining major feature development with the upgrade process to keep things organized and avoid unnecessary complexity.
- Regular updates are key: updating Angular regularly keeps your app secure and maintainable. If you let versions stack up, you risk falling behind again, and future upgrades can become much more disruptive and time-consuming.
Following these practices will make the upgrade process smoother and more predictable in the long run.
Conclusion
Upgrading Angular in a complex project is no small task, but with careful planning and a step-by-step approach, it’s entirely manageable. By taking the time to migrate between versions properly and addressing key challenges, we were able to modernize the application while maintaining stability. The upgrade not only improved performance and maintainability but also set the stage for quicker, smoother updates in the future.
If you’re facing challenges with an upgrade, unsure where to start, or simply need a second pair of eyes, reach out. We specialize in Angular, and we’re here to help. Whether you need strategic guidance or hands-on support, we’ll help you move forward with clarity and confidence. Let’s discuss your case in a free 30-minute meeting.