đŠ Keep Product Teams Shipping Faster with Successful Frontend Migrations (#80)
March 26, 2025The company wants more features, faster. You go to your boss and suggest that reducing build times could increase the team's shipping velocity. They tell you that they aren't willing to invest in any system migrations to allow developers to ship high quality code at a faster speed. The company also won't hire more developers. The only option left is for the existing developers to work harder and faster, piling more debt onto a poor foundation until work comes to a relative standstill and the company's star engineers burn out and quit.
Have you been in this situation? I certainly have. Will Larson wrote:
"Migrations are the only mechanism to effectively manage technical debt as your company and code grows. If you donât get effective at software and system migrations, youâll end up languishing in technical debt. (And still have to do one later anyway, itâs just that itâll probably be a full rewrite.)"
Luckily, some companies understand that migrations help the company provide more value to customers. They must find a balance between building new features and improving the underlying infrastructure. They start to build out teams who execute the majority of large-scale migrations in order to keep product teams shipping quickly. You guessed it, I'm talking about platform teams.
Migrations on a frontend platform team
If you're not familiar with frontend platform, take a moment to read this blog post.
On a frontend platform team, we have to run migrations all of the time. Some common migrations that I've been a part of in the past include:
- Flow to TypeScript
- Emotion to CSS modules
- Jest to Vitest
- Craco to Vite
- Yarn to pnpm
- Eslint to Biome
- Any dependency upgrade with breaking changes
- Legacy design systems components to new design systems components
I wanted to take the opportunity to share how I approach migrations, in case you have one on the horizon and aren't sure where to start.
1. Define business value
Make sure that you have a clear definition of what value the migration brings to the business. When you run a migration, it may seem obvious to you why it is needed. But remember that you are probably one of the closest people to the problem, and it likely affects you the most. As you go up the chain, leaders must juggle thousands of problems across the organization. They need to ensure that everyone works on the most valuable tasks. What feels most valuable to you may not be the most valuable work for the business' primary goal, which is to make money.
When you evaluate business value, consider how long the project will take. You can use a decision matrix to determine whether you should take on a migration.
Aim for projects in the Quick Wins category at first. If the frontend platform team is relatively new, this will help you to gain the trust of the organization. Since no one has had the bandwidth to work in this area until now, there should be plenty of low-hanging fruit.
Make sure you avoid Thankless Tasks, since these will drag on forever and will reduce the level of trust that the business has in your team. If you discover that a migration is in the Thankless Tasks category while you're doing it, abandon it. Don't fall for the sunk cost fallacy.
2. Determine what success looks like
It's not enough to say that a migration will provide business value. You need to measure the success of the project so that you can prove that it did provide business value. Remember to capture a baseline so you can show the improvement you've made once the migration is complete.
Examples of how to evaluate success
For example, if we migrate from Jest to Vitest, how much faster will it be to run our tests locally? How much faster will CI be? How does this impact shipping velocity?
What if we're migrating from Emotion to CSS modules? How much faster do our top 5 pages load? How does this impact our core web vitals?
Let's say we're migrating from JavaScript to TypeScript. Can you look in Sentry for runtime bugs? Can you estimate how many of these bugs will no longer exist once you migrate to TypeScript? Can you look at the most recent production incidents your company has had and determine whether any of them could be prevented by using TypeScript instead?
Once you decide what success looks like and how to measure it, you can use tools like Honeycomb.io to track it. You can set up SLOs to make sure that your application or systems aren't regressing. This is what you'll show to leadership once you complete the migration to prove that your hypothesis was correct, and it was worthwhile to complete the migration.
3. Set up backstops
The most important aspect of running a migration is setting up backstops to prevent the codebase or system from regressing while you're trying to move it forward. You need to determine whether there are any rules that you can put in place to ensure that all new work will be done in the new way, otherwise you'll find yourself in a Sisyphus situation.
Some examples of backstops are:
- lint rules preventing devs from importing a legacy component or library, with guidance on what to use instead
- custom rules in CI that fail the build if a certain dependency is detected
- SLOs in your observability tool of choice, which can detect whether the instances of whatever you're trying to get rid of is increasing
4. Automate as much as possible
The less manual work you and your colleagues need to do, the better. Once the appropriate backstops are in place, start thinking about automation. How can you automate 80% or more of the migration? Depending on the type of migration, you can use off-the-shelf codemods or write your own. You can make use of your IDE by writing regexes that will find the imports you'd like to get rid of and replace them wholesale. You can use a tool like Codemod or Grit.io.
Big bang migrations
Some migrations have to be done all at once. For example, migrating to a new bundler or dependency manager needs to be a "big bang" migration.
This is the riskiest type of migration, and you need to ensure you have a strong business case for it.Figure out how to derisk the effort since you can't deliver it incrementally. Make sure you do proof-of-concepts and set up metrics for what the value to the business will be if you succeed.
And pro tip, know that your initial estimates will always be too shortââpad your estimates.
Incremental migrations
Other migrations can be done incrementally. Once you've figured out how to automatically migrate most of the codebase, figure out if you can ignore anything that hasn't been migrated yet. My opinion here (and this may be controversial), is that it's okay to never finish these types of migrations. Eventually, the ignored code will be refactored and rewritten. If it isn't, it probably means it isn't causing a problem and it's not worth the effort.
5. Profit đ
Now that you have completed your migration, you should have all of the metrics in place to prove that it was successful. Go on a roadshow. Explain your process and why what you did was valuable. This will buy you the opportunity to accomplish even bigger and more meaningful migrations, and will help your organization to understand that running successful migrations doesn't just make the lives of engineers easierââit improves the product for customers too.
As always, I'd love to hear from you! Have you run a migration recently? What did you migrate? Was it successful? Was there something you wish you had done differently? Reply to this email and letâs discuss!