How I scaled a frontend platform to 18 apps

3 min readยทFeb 19, 2026

Four years. One codebase. A platform that kept growing faster than the tools that managed it. This is the story of every infrastructure problem I ran into - and what I built to solve them.


The Routing Problem - Building Filesystem Routing Without Next.js

With 11 sub-applications and growing, every new page meant manually editing a centralized route file - 120 routes, all in one place, each wired by hand with its path, component, permission, and breadcrumb.

So I built a custom webpack loader that turned the filesystem into the router - create a file and the route exists.

Results

  • Eliminated manual route configuration
  • Merge conflicts on route files eliminated
  • Faster developers onboarding

๐Ÿ”— Deep dive: "Building Filesystem Routing in CRA".


Migrating CRA to Next.js, Incrementally

CRA was being deprecated. A direct migration to Next.js broke immediately - env variables, SSR conflicts, bundler transpilation differences. Too risky to fix all at once across a 2,000-file codebase.

So I patched CRA to progressively align with Next.js - one step at a time, without breaking what was already working - until the two were so aligned that the final commit touched just 18 files.

Results

  • Changes required to migrate to Next.js were reduced from 405 to 18 files
  • Instant client-side navigation preserved
  • Zero breaking changes in production
  • Full rollback possible with one commit revert

๐Ÿ”— Deep dive: "Migrating a 4-Year CRA Codebase to Next.js".


Rearchitecting i18n Layer

Every app kept its own locale files, and translation keys followed deeply nested paths - unreadable, duplicated across apps, and impossible to auto-translate.

The fix was simple in concept: use the exact text shown to the user as the key - something a translation script could finally work with. Simple, but not something you could apply to 10,000+ usages by hand - so I built a codemod to do it in one pass.

Results

  • Reduced bundle size by 2.4MB
  • More readable codebase
  • Reduced manual translation work for developers

๐Ÿ”— Deep dive: "Rearchitecting i18n Layer".


Building an Automatic Translation Pipeline

With self-describing keys, automatic translation became possible. I built a script that scans for new strings and auto-fills missing translations, plus a CI linter that blocks any merge request with an untranslated key before it ships.

Results

  • Increased translation coverage from 40% to 100%
  • Zero manual translations

๐Ÿ”— Deep dive: "Building an Automatic Translation + CI Linter".


Migrating 300+ Files to TailwindCSS in just a second

When the team adopted TailwindCSS, we had 364 files of inline styles to migrate. At 20-30 files a day manually, that's two weeks of work. I searched for an existing tool to automate it - nothing existed - so I wrote one.

Results

  • 364 files migrated in a single script execution
  • ~2 weeks of manual work done in one run
  • Eliminated style/className conflicts across the entire codebase
  • Performance improved: No more inline style objects, no more unneeded re-renders

๐Ÿ”— Deep dive: "Migrating 300+ Files to TailwindCSS in just a second".


Replacing MUI with TailwindCSS: A 12x Performance Gain

React 19 broke MUI v4. Rather than upgrading to MUI v5, I cloned the MUI source code, read through it component by component, and rebuilt every component as a 1:1 equivalent in TailwindCSS.

Results

  • 3x-12x faster render times across 25 components
  • 20% bundle size reduction from removing MUI entirely
  • Zero visual regressions in production

๐Ÿ”— Deep dive: "Replacing MUI with TailwindCSS: A 12x Performance Gain".


From Webpack Loader to Building an Internal Framework

Routing, app discovery, and sub-application registration all used to depend on a custom webpack loader - which meant a slow dev server, slow hot reload. The fix was to pull all of that into an internal framework running independently of any bundler.

Results

  • Sub-application registration automated
  • Dev server startup: ~30s โ†’ ~10s (67% faster)
  • Hot reload: ~5s โ†’ near-instant
  • ~30 minutes saved per day across the team

๐Ÿ”— Deep dive: "From Webpack Loader to Building an Internal Framework".


Every problem in this post had the same shape: the platform grew faster than the tools that managed it. My job, consistently, was to close that gap - identify the friction, build the tool, and make sure the new system was meaningfully easier than what it replaced.

Good infrastructure means your team delivers faster without knowing why.


Questions, feedback, or want to talk architecture? Reach me at alirezawbhr@gmail.com