The Problem We Were Solving
When I joined Nubank's web platform team in 2022, we had a classic microfrontend setup: a single shell application built with Create React App, federating six product domains via Webpack Module Federation. On paper, it was clean. In practice, every deployment was a negotiation.
Version pinning across six teams meant any major dependency update required coordinated releases. Our shell had become a bottleneck — the very thing microfrontends are supposed to eliminate.
The TanStack Start Proposal
TanStack Start's file-based routing and server function model map naturally to a microfrontend shell. Each route file can lazy-load a remote module while keeping type safety end-to-end — something that was essentially impossible with the old setup.
// Before: untyped dynamic import
const RemoteCheckout = React.lazy(() => import('checkout/App'))
// After: typed server function fetching route config
const routeConfig = await getRemoteRoutes({ domain: 'checkout' })
The shift to server functions also meant we could do route-level A/B testing without client-side conditionals cluttering every component.
What Actually Broke
Not everything was smooth. Our legacy analytics integration assumed window.__APP_SHELL__ to be set synchronously on load — an assumption that SSR immediately violated. We spent a week debugging phantom page views before tracing it to hydration timing.
The Outcome
Three months post-migration: deploy frequency up 2.4×, zero cross-team version conflicts in Q1 2026, and our Core Web Vitals LCP improved from 2.8s to 1.4s on a P75 mobile connection.
The architectural lesson: frameworks that align with your deployment model remove whole categories of problems. TanStack Start aligned with ours.