How I designed a migration through a business pivot with the Strangler Fig pattern

Recently at work, we've had to deal with a business pivot, yet again. My intuition told me it would happen, which is why I kept the system's architecture flexible. Let me introduce you to the core problem, how I've been solving it, and how you could prevent similar things from happening in the future.
1. The business change
V1: location as the unit (January to May 2026)
In V1, we treated every location as its own tenant, so the app was multi-tenant at a granular level, exactly as the requirements of January 2026 asked for. My CEO's words:
Location is the primary unit of experience.
Pricing is per location.
Users interact in a location.
Posts and chats are never shared across locations.
Brands are labels only; locations are the product.
Do NOT merge locations into one shared feed.
One honest note on what running means here. V1 reached production for one brand (Edge Fitness) and ran there for a short window. Everything else in those months was the building process and early demos. I am writing that down because it is easy to call months of building and demoing a launch, and it was not one.
The pivot (V2), May to June 2026
Weeks after that launch, on May 29, my CEO said it plainly: the current business model would not scale and the logistics were hard to manage, so we should merge related tenants into brands and create one global app per brand.
My mistake? I had married almost everything to the local tenant_id.
I adapted because the schemas were flexible and I knew the codebase well. The reasoning was profit: brands were where the revenue came from, and individual locations weren't profitable.
Then the company shut down in June 2026, before this migration finished. That is where the story actually ends, and I would rather write that than imply a half-finished migration shipped.
2. The strangler fig pattern
The strangler fig pattern is where you build the new system alongside the old one and let it gradually take over. That is how I approached the brand migration, with the understanding that it was still in progress when we stopped:
We built the new admin features for brands. In a B2B product, you always maintain two systems: the customer-facing app, and the admin one that owns the system data, reports, user management, and metrics.
We kept authentication almost unchanged and extended a few API endpoints to return the new fields.
For the brand and social features, we built a V2 of the API where the logic hangs off the brand instead of the location.
We added graceful degradation in the frontend, redirecting a user from their location to the brand page once they had been migrated.
None of it finished. What I did finish was the design and most of the migration path, and the lessons below are what I would carry into the next attempt.
3. Don't add everything they ask you for at once
The team and I were asked to introduce the following as well:
Filters and being able to search users by brand
User location preferences: geolocation and extending existing locations
I added these features to the backlog as they were pure scope creep.
Once we've shipped this new system and we've accomplished the given business goals, we can keep enhancing the existing foundation we built. You cannot build on broken foundations.
4. Continuing the migration
Add the brand_id to the social-related tables and make them nullable while we perform the migration process, and stop using location_id entirely in the new API to match the new business context.
Migrate users from locations to brands using a membership table, where we also had the location_id. We migrate our users both in-app through endpoints like "/me" and using a startup script triggered by a feature flag.
Don't make new columns non-nullable until the migration process is done, and don't remove the location_id yet until the new migration strategy works for 100% of users. We always need backwards compatibility in case of a disaster or a wrong business plan.
5. Lessons learned & conclusion
Multi-tenancy is hard. You won't get it right at the first attempt, and even if you do, you'll have to deal with RLS (Row Level Security) and complex RBAC permissions.
Keep your schemas and architecture flexible in the initial startup stage. There will be pivots, and your code needs to adapt to the business, not the other way around.
Learn how to learn from pivots and changes in business directions. You're getting paid to solve problems; some of them are interesting, others are not so fun, but you still have to find meaning during the process.
I've been improvising lately on the electric guitar, where you have to adapt your skills to others' music; the same happens with startups: adapt your skills to the business, not the other way around.
I'm currently building Luna Labs and helping founders in the pre-seed and seed stages build AI products and internal tools/automations, and I own the full stack, from planning to building to deployment. You can learn more here: https://www.itsfranciscoluna.com/



