Let me cook 🔥
"The App Router is the future of Next.js," they said. "It's better in every way," they said.
They weren't wrong. But they also didn't mention the hydration errors. The streaming issues. The "use client" directive confusion. The three days of my life I'll never get back.
Day 1: Optimism
Moving files from pages/ to app/. Easy enough.
`
pages/
index.tsx → app/page.tsx
about.tsx → app/about/page.tsx
tales/[slug].tsx → app/tales/[slug]/page.tsx
`
Layouts are great! No more _app.tsx wrapper hell.
`tsx
// app/layout.tsx
export default function RootLayout({ children }) {
return (
`This is nice. This is really nice.
Day 2: The Hydration Hellscape
`
Error: Hydration failed because the initial UI does not match what was rendered on the server.
`
Over. And over. And OVER.
The culprit? Browser-only APIs in server components.
`tsx
// ❌ This breaks everything
export default function Component() {
const width = window.innerWidth; // RIP
return
// ✅ This works 'use client'; export default function Component() { const [width, setWidth] = useState(0); useEffect(() => setWidth(window.innerWidth), []); return
`Every component that touched localStorage, window, or document needed the 'use client' directive.
Day 3: The "Use Client" Avalanche
Once you add 'use client' to one component, it spreads. Like a virus.
Parent has client code? Client component. Child of client component? Also client. Child's child? You guessed it.
I ended up with more client components than server components. Defeats the purpose.
The fix: restructure. Keep client logic in small, leaf components.
`tsx
// Server component - does the data fetching
export default async function Page() {
const data = await fetchData();
return
// Client component - handles interactivity
'use client';
function ClientInteractiveWrapper({ data }) {
const [state, setState] = useState(data);
// ... interactive stuff
}
`
The Payoff
After the migration: - First Contentful Paint: 40% faster - Time to Interactive: 35% faster - Bundle size: 25% smaller
Worth it? Yes. Painful? Also yes.
🔥

