DEV Community

Cover image for Icarus and the npm Updates: How Version Control Rescued My npm Upgrade Nightmare
Oheneba Poku-Marboah
Oheneba Poku-Marboah

Posted on

Icarus and the npm Updates: How Version Control Rescued My npm Upgrade Nightmare

Story time. So, I just inherited a chaotic work project that felt completely out of control. I had to take a moment to gather my thoughts before diving in. Time to roll up my sleeves and tackle this mess!

The Starting Mess

I inherited a project that had spiraled into a state of - well it was in some state for sure. No version control. Instead, a graveyard of duplicated files named things like old_filename.extension and even a collection of zipped folders that served as backups whenever something got changed.

To be fair, the project worked, and that counts for something. Whoever built and maintained it—whether it was one person or multiple—was probably thrown into the deep end and made the best of their situation. I respect that "get-it-done" energy.

Step 1: Implementing Version Control

Before touching a single file, I set up version control. If I messed anything up, I needed a way to revert changes easily. My initial commit had over 100 files, many of which were redundant.

Running:

git show --pretty="" --name-status
Enter fullscreen mode Exit fullscreen mode

showed me the list of files in that commit, including all the old_filename.extension artifacts.

To keep track of my thought process and ensure that whoever inherited the project after me had some documentation, I created a decisions.md file. In it, I documented the state of the project when I found it and the cleanup I was able to do within my limited timeframe. My knowledge of Git was definitely stretched during this process, which was a bonus learning opportunity.

I introduced software best practices:

  • Version control
  • Reusability (DRY principle)
  • Documentation
  • Removing unused files and dependencies (as much as time allowed)

And then, finally, the main point of this article: Updating the npm packages.


Checking Outdated Packages

To check outdated npm packages, I ran:

npx npm-check-updates
Enter fullscreen mode Exit fullscreen mode

which gave me the following output (grouped manually into minor and major versions).

Minor Versions:

package A           ^1.19.0  →  ^1.20.3
package B           ^1.7.4   →  ^1.8.0
package C           ^1.4.5   →  ^1.4.7
package D           ^3.1.6   →  ^3.1.10
package E           ^1.14.0  →  ^1.23.9
package F           ^4.17.1  →  ^4.21.2
package G           ^1.17.1  →  ^1.18.1
package H           ^3.1.0   →  ^3.1.1
package I           ^0.2.0   →  ^0.2.1
package J           ^0.4.1   →  ^0.7.0
package K           ^8.5.1   →  ^8.13.3
package L           ^2.3.3   →  ^2.3.4
package M           ^3.0.2   →  ^3.0.3
package N           ^6.9.0   →  ^6.37.5
Enter fullscreen mode Exit fullscreen mode

Major Versions:

package O           ^0.16.0  →  ^1.0.4
package P           ^10.0.0  →  ^16.4.7
package Q           ^2.2.4   →  ^3.0.7
package R           ^2.0.12  →  ^3.1.9
package S           ^4.5.2   →  ^6.3.0
Enter fullscreen mode Exit fullscreen mode

This project hadn’t taken a shower in a while. Five packages had to jump at least one major version, two had to jump more than one, and one package had to upgrade by six major versions. SIX! Some wars have lasted fewer days than that -  I am looking at you, Anglo-Zanzibar War.

Oh, and Bootstrap was in the .gitignore, so even that required a manual backup just in case my update completely wrecked the UI. You know the unthinkable happened, and the roundness of the buttons affected sales


The Update Process

I started naturally with patch updates:

npx npm-check-updates -t patch -u && npm install
Enter fullscreen mode Exit fullscreen mode

Smooth. No issues. Committed the changes.

Then, minor updates:

npx npm-check-updates -t minor -u && npm install
Enter fullscreen mode Exit fullscreen mode

Tested it. Everything was fine. Committed again.

Then came the major versions. At this point, Icarus was soaring with his wax wings. Instead of going one package at a time, I decided to take a shortcut and upgrade everything at once:

npx npm-check-updates -u && npm install
Enter fullscreen mode Exit fullscreen mode

Why not? I had backups. I had version control. This was controlled chaos, right?

IT. DIDN’T. WORK.

Cue the surprised Pikachu meme.

Back to One-by-One

I reverted and took the slow route:

  • Removed completely unused packages
  • Updated packages from smallest jump to largest
  • Tested thoroughly

The biggest offender? dotenv, which had to jump six major versions. Fortunately, it does exactly one thing in most projects, so I updated it with confidence:

npm install dotenv@latest
Enter fullscreen mode Exit fullscreen mode

No issues.

Then came nodemon—another easy one. Also, it updated smoothly.

Now, three remaining major updates, but first—a detour into unused packages.


Tracking Down Unused Packages

To check if a package was actually in use:

npm ls <package-name>
Enter fullscreen mode Exit fullscreen mode

Then, as a second check, I searched the entire codebase in VS Code.

A third approach:

npx depcheck
Enter fullscreen mode Exit fullscreen mode

which gave me something like this:

Unused dependencies:
Package A
Package B
Package C

Missing dependencies:
Package J: ./index.js
Package K: ./index.js
Enter fullscreen mode Exit fullscreen mode

Not 100% reliable—some "unused" packages were actually required. (RIP, pug. Uninstalling it broke everything.)


The Last Two Major Updates

Back to the 2 remaining major versions. Wait, what's that? Oh, it's just the sun being too close again—oooh, my wings are melting.

The app; crashing. Even before I attempted the major version update? Sigh!

Icarus had to deploy the parachute. I had been making commits regularly so that I could always revert. There indeed had been a breaking change when I updated the minor versions because suddenly, I was getting an error when logging out. I had to put on my git detective hat and go snooping for the point in time when it stopped working. My first guess, passport.js, when I arrived in that commit update, turned out to be correct. The bump in passport.js had broken the log-out functionality. So I checked out that commit and switched back to the older version of passport - to be handled later.

For the last time, back to the last 2 major version upgrades. One of them gave me no problems. The last one had some breaking changes, which means I had that and passport.js to take care of before I was done. But they both ended up being fixed within a day.

Wrapping Up

So that was the story of how I had to upgrade some decayed packages in an npm project. What started as a soup of outdated packages, missing version control, and abandoned dependencies ended up cleaner, more maintainable, and fully documented.

Would I do it again? Sigh! I got paid so... just kidding I ended up learning more about git and npm on this project than I ever imagined I would. No kidding - there is a senior dev I look up to who said he had never had to go down some of the git and npm rabbit holes i went down during this project. So would I do it again? Probably. But next time, I might just start with one package at a time instead of playing Icarus.

Lesson learned.

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post