For a recent project, I had to reopen an old website we’d built years ago with Jekyll. The moment I saw the code, I put my hands on my head: fossilized dependencies, forgotten plugins, and a workflow that felt like it came from another era. That experience sparked a reflection that goes beyond that single project:
What happens when time catches up with software? And what does it mean—today, in the age of AI and tools that evolve every six months—to find yourself working on a piece of technological history that no longer keeps pace?
For those who don’t live in code every day: software isn’t a single block, but a collection of components that work together—frameworks, libraries, plugins, dependencies. Each of these evolves over time through updates, patches, and new versions. When one piece stops moving forward, or becomes incompatible with the rest, the whole system starts to creak. It’s a bit like trying to run a modern app on a ten-year-old smartphone.
The cost of obsolescence
In software, time moves at a different speed. Six months can be enough for a project to lose its freshness, a year for it to become hard to touch, and five years for it to feel written in another language.
Revisiting an old project is like opening a time capsule: you find vanished libraries, clunky patterns, and tools nobody uses anymore. It’s not just nostalgia—it’s proof of how fast technology moves, and how standing still really means falling behind. That’s exactly what happened with this project: a site built years ago with Jekyll, a static site generator that used to be a popular choice for web developers.
The problem? Today, the landscape has completely changed. In a world where frameworks like Next.js dominate, going back to Jekyll wasn’t just a trip through time—it was a reminder of how quickly technology can turn from enabler to obstacle if it’s not kept up to date.
1. Toxic dependencies and code archaeology
A bit of context first: after finishing the project, years ago we handed it over to the client, who managed it independently from then on. But from that point forward, the codebase was never updated—no new dependencies, no refreshed libraries. Probably because Jekyll, being a static site generator, didn’t pose major security risks and didn’t seem to require much maintenance. The problem is that this “apparent peace” hides a cost.
When we were called back for a redesign based on the same codebase, the developer experience turned into a small nightmare. The first challenge was simply getting the project to run again. Incompatible Ruby versions, deprecated dependencies, and unmaintained plugins made every step a puzzle. The official documentation was outdated, and finding modern solutions felt like doing digital archaeology. But the real issue wasn’t just the outdated libraries—it was the code itself.
There was no type system, meaning no way to know in advance what kind of data a variable could contain or how it was being used. Without that guidance, navigating the code was tough: no clear structure, no data map. Working on a project like that feels like reading a book with half the pages torn out—you can guess the story, but the risk of getting it wrong is high.
With a modern stack like Next.js and TypeScript, it would have been a completely different story. Next.js is a JavaScript framework designed for fast, flexible web development, with built-in tools to improve performance and streamline the workflow.
TypeScript, on the other hand, adds type checking to JavaScript—it lets you define what kind of data you’re working with and catch errors before they ever reach production. Without robust typing, every change feels like a leap in the dark: debugging turns into a treasure hunt, and even trivial bugs can waste hours. That’s why we use TypeScript for most of our projects—not just to write safer code, but to work more calmly and efficiently.
Read more: Why to use a static type checker when building JavaScript apps.
2. A workflow at snail’s pace
The client’s request was simple: update some content and add a few new sections. In theory, nothing complicated. In practice? A nightmare. Every small change in Jekyll required rebuilding the entire site. No hot reload, no real-time updates, no dynamic previews—nothing like what I’d have with Next.js and Sanity, which let you see changes as you make them.
The result? Every operation took longer than it should, and the fact that I hadn’t touched Jekyll or its Liquid templates in years didn’t help. Once again, the lack of clear typing made things worse.
With TypeScript, I would’ve immediately seen which data properties were available, their types, and potential errors—before even running the code. With Jekyll, the only way to find out was to try, fail, fix, and repeat. Definitely not an ideal workflow. At one point, I realized I was fighting the tool itself instead of focusing on the work I actually needed to do.
3. Vintage software, modern problems
My impression is that Jekyll, built on Ruby, is still a solid and well-crafted tool—but it’s no longer at the center of the web landscape. Not because it doesn’t work (it does, and well), but because the way we build and maintain websites has evolved.
Today, many new projects are born on modern frameworks like Next.js or Astro, which offer faster workflows, smoother developer experiences, and a much broader ecosystem. That makes working with Jekyll a bit harder: fewer developers using it, fewer up-to-date resources, and a steeper path to troubleshooting.
I noticed this when trying to add a simple YouTube video, only to discover the available plugin hadn’t been updated in years. Nothing catastrophic—but enough to remind me how fragile old dependencies can become over time. And it’s not just a technical issue—it’s a human one. When software ages, it demands more time, more focus, and more patience. And over time, patience is often the first thing that runs out.
In search of lost (and expensive) time
All this translates into more time lost and higher costs. A simple change took me hours—hours that could have been spent on something more valuable if I’d been working with modern tools.
Then there’s maintenance. When you’re working on an outdated project, you don’t just write code—you spend your time figuring out how to make things work without breaking everything else. It’s like trying to repair a vintage car without the right spare parts: every little fix is a battle, and every solution takes longer than it should.
And then there’s security. Many people underestimate how even seemingly simple software—like static websites—relies on libraries and packages that need regular updates. If those dependencies aren’t maintained, they can slowly become sources of vulnerabilities or unexpected malfunctions.
And that’s true for everything, even modern frameworks like Next.js: every ecosystem evolves, and keeping up takes continuous attention. In the end, the real cost of falling behind isn’t just technical—it’s economic and mental. For clients, it means paying more to get less. For developers, it means losing time on avoidable problems and building frustration. That’s why letting a project go stale is never a good idea. Sooner or later, the past will send you the bill—and it’s rarely a small one.
Developer Experience = Business Value
Working with modern tools isn’t just about developer comfort—it’s a strategic choice that directly affects product quality and business results. Updated software is easier to build, more stable to maintain, and safer in the long run. Fewer bugs, fewer emergencies, fewer surprises.
It also improves user experience. A modern infrastructure makes it possible to iterate quickly and adapt the product to real user needs. If every small change takes days because the codebase is fragile, you risk standing still while the market moves forward.
Finally, there’s an element of attractiveness. People in digital can easily spot the difference between a product that’s well-maintained and one that’s been left behind. And that applies to everyone—clients and developers alike. No one wants to work with an outdated stack that turns every update into a headache.
Legacy vs. Replatforming: when does it make sense?
Start from scratch or keep the legacy code? It’s a question many companies face when their software starts to age. The temptation to leave things as they are—“because it still works”—is strong. But working doesn’t mean being efficient.
As software grows old, it slowly becomes a bottleneck: new features are harder to add, bugs take longer to fix, and every change carries hidden risks. Meanwhile, technology keeps advancing. The solution isn’t always to rewrite everything from scratch. A more sustainable approach is gradual modernization—updating the stack step by step, starting from the areas that cause the most friction.
Replacing obsolete modules or introducing new technologies incrementally allows systems to evolve without halting operations. In this sense, updating isn’t just a cost—it’s an investment. It delays obsolescence, reduces risk, and keeps the product aligned with business needs. Waiting for something to break, on the other hand, is usually the most expensive strategy of all.
The future is now
Every line of code we write today will be legacy tomorrow. That’s inevitable. But that doesn’t mean chasing every new trend or rewriting everything every two years. The key is to design for maintainability—to build software that can evolve gracefully over time.
Delaying updates might feel easier in the short term, but it’s an illusion. The longer you wait, the more rigid and costly your code becomes. And when you finally have to act, the bill is always higher. Today, the challenge isn’t just keeping software up to date—it’s learning how to take advantage of new opportunities.
Artificial intelligence is transforming the way we build, test, and optimize software. It doesn’t replace developers—it amplifies their capabilities. Tools like Cursor, GitHub Copilot, and assisted refactoring systems don’t write code for us, but they help us focus on what truly matters instead of drowning in repetitive maintenance.
Keeping your stack current, then, isn’t just about using newer versions. It’s about rethinking how we build software altogether—making it more scalable, secure, and sustainable. If there’s one thing I learned from revisiting that old project, it’s this: Updating today means saving tomorrow. It’s not just about avoiding technical issues—it’s about keeping pace with the future, before the past inevitably sends the invoice.
Read more: AI is the future of development, but not as I imagined.

