Data analyst, postgraduate in Data Science, and electrical engineer by training.
A couple of months ago I sat down with the CTO of a scheduling SaaS for clinics. Live product, paying customers, around forty thousand bookings a month. He wanted to show me a silly bug in the appointment reminder, an SMS going out with the wrong date, and midway through he realized he couldn't even run the project on his own laptop without a fight.
A clean clone wouldn't come up. It was Node 14, which stopped getting support back in 2023, and a date library three major versions behind what the rest of the world runs. It took two days to get the thing compiling again. That wrong reminder, meant to ship the same day, waited nine.
What struck me wasn't the delay. It was that nobody, at any point, had decided to leave that stack behind. Every sprint had a good reason to postpone the upgrade. Stacked together, the good reasons became a product nobody can touch without flinching.

A dependency nobody updates is like old pipe behind the wall: fine until the day you have to open everything up.
There's almost never a meeting where someone says "let's stop updating the stack." It would be easy if there were, you could argue against it. What there is instead is a run of sprints where bumping a dependency loses, every single time, to a new screen the client asked for. The screen shows up in the demo. The upgrade shows up nowhere, until the day it blocks everything.
And here's an incentive worth naming out loud. A vendor paid to ship features, full stop, has no reason to spend half a sprint bumping a library the client will never see. If they only touch the code when something breaks, preventive maintenance is literally work nobody will thank them for. The bodyshop dressed up as a squad lives on exactly this: it charges for presence and answers for no upkeep at all.
I'll be fair, because it isn't all cold math. A lot of it is just the obvious: updating dependencies is dull, thankless work, and it's never the most urgent thing on the board. The problem is the absence of any decision, repeated fifty times over. And what freezes along with the version isn't only the code: it's the people you can hire to work on it and the list of security holes you can still close.
The most expensive way to learn your stack has frozen is through a security advisory. I watched it happen at a company that had to close a known vulnerability in a dependency, the kind of thing that should be a "bump the version, done." Except bumping that version pulled another, which pulled another, a chain reaction of three years of deferred updates. It ran close to forty thousand reais of rework over nearly three weeks.
And I rounded that number up on purpose, I'll admit: some of it was refactoring they'd have done anyway. But even cutting a third, it's still far too expensive for a problem nobody chose to have, one that landed in the exact week the team had another release to close.

The cost of keeping a stack current never shows up on the monthly invoice. It waits, piles up, and charges all at once.
There's one more line item almost nobody adds up: hiring. A dead runtime scares off good engineers. No senior wants to spend the day maintaining a version that fell out of support, and the people who know that old stack inside out are the ones on their way out, carrying the knowledge in their heads. You don't just end up with a product that's hard to maintain. You end up with a product that's hard to hire for, which is a good deal worse.
You don't need a formal audit to catch the smell. You can run a quick check yourself, or ask whoever owns your code to answer it in front of you. Four questions.
Open endoflife.date and look up the version of Node, Python, Ruby or PHP running in production. If the end-of-support date has already passed, you're not "a bit behind." You're already running something nobody out there patches anymore.
Take the five libraries that show up everywhere in the code. If any of them is two major versions or more behind current, there's a wall forming, and it only gets taller while nobody looks.
Search your git history for the last commit whose sole purpose was updating a library. If you have to scroll back months to find it, upkeep isn't a routine in your shop. It's an emergency waiting for its moment.
Clone the project into a fresh folder, follow the README to the letter, and time it. If it runs past an afternoon, the environment has already turned into tribal knowledge, and tribal knowledge is the most fragile thing a product can own. Two days, like the SaaS I opened with, is a scream.
That four-question check is roughly what we run on the first read of a client's code, in the Diagnostic Sprint, before writing a single line. It puts on the table in two weeks what usually becomes a crisis in six months, and if you want to see it up close, that two-week diagnostic is where to start.
What sets apart a squad that will maintain what it writes isn't greater talent, it's staying. People who know they'll live with the codebase a year from now treat updates as routine: a little each sprint, one dependency at a time, never the heroic weekend migration that becomes team legend. At Revin that's a house rule, not a favor: dependencies move through the same flow as the rest of the work, with the same care as a feature.
The scheduling CTO asked me, a bit sheepishly, whether his case was serious. I told him no, and I meant it: serious is when it locks up and makes the news. His was still in the quiet stage, the one you can fix without drama, as long as someone owns the routine. Our cases tell that story better than I can, because they show the before and after.
If you read this far and can't say off the top of your head which version your product runs on, that's your cue for the twenty-minute, four-question check. And if the answer rattles you, book a call with us and we'll look at it together, since fixing it with company tends to run a lot cheaper than fixing it alone.
6 read minutes
Article content: