How I led the migration of a SaaS product from a legacy Vue 2 to Vue 3 without stopping production at fabriq
When I joined Fabriq, we had a clear technical debt problem slowing down our delivery velocity. While my previous post covered building the team after fundraising, this one focuses on how we tackled one of our biggest technical challenges, migrating from Vue 2 to Vue 3 while continuing to ship features.
Understanding the Nature of Technical Debt
Let me be clear about what technical debt meant at Fabriq. At the code level, we had defects tied to poor patterns, inconsistent naming conventions, and most critically, zero tests on our web application. Our Document Management System carried extensive business logic and complex user flows, which made the need for testing all the more critical.
The absence of tests meant our code became legacy the moment we wrote it. Every new line of code added to this legacy pile. You might think the solution is simple, just add tests and move on. But the reality was more complex.
The Root Problem
For historical reasons, during the early years of development of the product, there were no testing strategies in place.
When I arrived, our frontend was running Vue 2 with custom patches applied to use a store library designed exclusively for Vue 3. This unconventional setup created a major obstacle, the component testing library we wanted to introduce wasn't compatible with our patched store configuration.
This meant we had no choice but to upgrade to Vue 3 first. Beyond enabling testing, migrating to Vue 3 would bring other benefits, improved developer experience, performance, access to new features, and continued security patches.
This migration effort had been underway for almost two years without completion, and it was actively slowing our delivery. The lack of test coverage created fear among engineers, making them hesitant to refactor or improve code. I call this phenomenon system sclerosis, and it was becoming critical, we needed to regain control of our system.
Why Component Testing Matters
At this point, we need tools that allow us to rework the code with confidence that no regressions have been introduced.
Component integration tests validate the behavior of individual frontend use cases using a black-box testing strategy. The goal is to detect bugs as early and as quickly as possible by avoiding testing implementation details, since the SUT (System Under Test) will likely be refactored.

These are not end-to-end tests and do not provide the same level of certainty, but they give us a good degree of assurance with a very short feedback loop. This loop is short enough to use watch mode during refactoring or test-driven development, unlike e2e tests which do not provide an acceptable developer experience for use during the development process.
Component tests do not provide the same level of certainty as e2e tests but at this stage they offer sufficient confidence. Their fast feedback loop allows developers to iterate quickly during refactoring and test-driven development.
In addition, for teams working with CI/CD pipelines, automated component tests serve as quality gates, providing rapid feedback and preventing defective code from reaching the production.
After identifying the problem and recognizing the opportunity to move away from legacy code by establishing a proper testing environment, I involved my team to present this initiative to our CTO. The project was fully aligned with our department's goals of improving system quality and fostering continuous improvement.
Our Migration Strategy
The Vue 2 to Vue 3 migration is known to be a complex and delicate effort. Instead of diving straight into code, we approached it as a phased transformation, validating assumptions early, maintaining quality at every step, and keeping the team fully aligned.
We began with a proof of concept to validate our migration path and identify potential blockers before committing to large-scale changes. Once validated, we integrated the official migration script into our CI pipeline so that every team became automatically responsible for maintaining Vue 3 compatibility.
Testing and collaboration were key. Our QA team worked closely with engineers to catch regressions early. To reinforce this feedback loop, we created a dedicated Vue 3 environment, a full production instance of Fabriq that we used internally for a week to surface issues before customer rollout.
Observability guided our confidence. We instrumented Sentry with a Vue 3 specific tag to isolate client-side errors and used Honeycomb to monitor infrastructure and performance metrics in real time during rollout.
The release itself was gradual. We deployed first to a medium-sized client, then expanded to larger ones, and finally rolled out to all customers as confidence grew.
Throughout this migration, feature development never stopped. We continued shipping new product value while upgrading our foundation, proving that technical excellence and product velocity can coexist when planned carefully.
What Made This Migration Successful
This blog post can't capture every problem we encountered during the migration. But what made this effort succeed was:
Clear vision: Everyone understood why we were doing this and what opportunities it would unlock, particularly around testing and developer experience
Collaborative teamwork: Engineers, QA, and leadership worked together seamlessly. The collaborative approach meant issues were caught early and resolved quickly
Motivated engineers: The team was genuinely excited about escaping legacy code and building on modern foundations. This intrinsic motivation drove quality and speed
Leadership support: Our CTO supported the initiative because it aligned with our department's objectives around system quality and continuous improvement
Strategic approach: Our phased rollout with strong observability gave us confidence at each step
The Path Forward
Completing the Vue 3 migration removed a major bottleneck that had persisted for two years. More importantly, it unlocked our ability to introduce component testing, fundamentally changing how we approach code quality and developer confidence.
Technical debt doesn't disappear overnight, and it certainly doesn't fix itself. It requires clear-eyed assessment, strategic planning, organizational alignment, and sustained effort. For us, tackling the Vue 3 migration was about more than updating a framework. It was about regaining control of our system and creating the foundation for sustainable growth.
With the migration complete, we're now positioned to implement the testing infrastructure that was our original goal. The feedback loops are tightening, engineer confidence is growing, and we're finally able to practice the continuous improvement that modern software development demands.
This is the second post in my series documenting my journey as an Engineering Manager at Fabriq. If you're interested in how we built the team from scratch, check out my first post about building a team after fundraising.