How to Move an Existing App Onto Your Shared Foundation
Building a shared foundation is easy on new apps. Retrofitting an old one is the hard part. Here is how to migrate a live app onto the foundation without a rewrite.
Retrofitting an existing app onto a shared foundation is a migration, not a rewrite, and treating it as a rewrite is how these efforts die. You move one layer at a time, starting with the layer that gives you the most leverage for the least risk, and you keep the app shippable the entire way. Most apps never need to be fully absorbed. They need the two or three foundation pieces that actually pay off, and they can keep their own quirks everywhere else.
I have pulled older apps onto the shared stack more than once. The ones that went well were the ones I did in slices. The ones that stalled were the ones where I tried to make the old app look like a freshly scaffolded one in a single pass.
Do not rewrite. Adopt one layer at a time
The instinct is to regenerate the app from the scaffolding CLI and port the features over. Resist it. A rewrite throws away every bug fix and edge case the old app accumulated, and it means the app ships nothing new for months while you rebuild what already worked. This is the demo to shippable gap in reverse: the boring accumulated correctness is the whole value, and a rewrite deletes it.
Adopt instead. Pick one layer, swap the old app's version for the foundation's version, ship it, prove it works, move to the next. The app stays live and improving the whole time. This is the strangler pattern applied to your own platform: you replace the old app's internals piece by piece until it runs on the foundation, without ever taking it offline.
Start with the layer that pays off first
Order the migration by leverage over risk. Some layers are high value and low risk to swap. Start there.
- Design tokens first. Point the old app's colors and spacing at the shared design tokens. This is nearly risk-free, visible immediately, and it makes the app look like it belongs to the family before you touch anything dangerous.
- Auth next, carefully. Moving to shared auth is high value because it is the thing you most want identical everywhere, but it is high risk because you can lock users out. Do it behind a flag, run both paths in parallel, and cut over once you have proof.
- Deploy and observability. Getting the old app onto the shared deploy pipeline and the shared logging means it now shows up in the same runbook as everything else. Big operational payoff, moderate risk.
- Shared components last, and only where they fit. The UI is where the old app has the most legitimate reasons to differ. Adopt shared components where they match and leave the app's custom screens alone. Forcing every screen onto shared components is how you turn a migration into a rewrite.
Keep the app shippable the entire time
The rule that keeps a retrofit alive: the app must be deployable after every single step. No multi-week branch where the app is half-migrated and cannot ship. Each layer swap is its own small change, tested and released on its own. If auth adoption goes sideways, you have not also broken the design tokens, because those shipped weeks ago and are already stable.
This is where characterization tests before you refactor earn their cost. Before you swap a layer, pin the current behavior with tests, so when you replace the internals you can prove the behavior did not change. Without that safety net, every swap is a leap of faith and eventually one of them breaks something you did not know was load-bearing.
Decide what to leave alone
Full absorption is usually the wrong goal. The point of a shared foundation is leverage, not uniformity. If the old app has a bespoke feature that no other product shares, there is no compounding value in forcing it onto shared code. Leave it. The line between shared and divergent applies to migrations too: adopt the layers that benefit from being identical, keep the app's genuine differences as its own.
A good retrofit leaves the app reading from the shared foundation for auth, billing, tokens, deploy, and logging, while its actual product surface stays its own. That is enough. You get the operational and consistency wins without paying for a rewrite you did not need.
When retrofitting is the wrong call entirely
Sometimes the honest answer is not to migrate. If the app is a candidate to kill, do not spend a month pulling it onto the foundation first. If it is stable, rarely touched, and shares almost nothing with the rest of the portfolio, the retrofit may cost more than it returns. Retrofit apps you will keep investing in. Let the ones on their way out stay where they are.
I run these migrations through the same build workflow at Bootspring, which lets me swap one layer, verify it against the rest of the portfolio, and ship, without ever taking the app down. Move the app onto the foundation the way you would eat an elephant. One layer at a time, shipping after every bite.