Skip to main content
Tutorial

Next.js App Router: How I Migrated a Real UAE Production Project

4 min read

Six months ago, I found myself elbows-deep in a Laravel-Next.js hybrid for a limo service client in Dubai, two weeks before their World Cup event deadline.…

Six months ago, I found myself elbows-deep in a Laravel-Next.js hybrid for a limo service client in Dubai, two weeks before their World Cup event deadline. The CEO wanted the app running on Next.js 13’s App Router to fix SEO issues from their old pages directory setup. Spoiler: it wasn’t a smooth ride.

The project, Tawasul Limo, had 80% of its frontend written in class components with a Redux store that grew into a monster. We’d been patching it for years—every prop drilling fix added more tech debt. When the client said “SEO matters more now that we’re advertising during the World Cup,” I knew the App Router’s server components were the right call. Just not how right.

First obstacle: Folder structure nightmares

The Pages Router felt like an old friend. Moving routes into /app meant rewriting dynamic [id] routes with the new page.tsx paradigm. One component broke because we’d hardcoded route names in a custom sidebar navigation drawer. Fixing that took me an afternoon, mostly because I kept double-checking the Next.js docs on parallel routes—still clearer than some open-source docs I’ve seen.

Data fetching drama

We replaced Redux with React Query. Not because I hate myself, but because Server Components forced data fetching into async workflows. Migration steps looked clean on paper:

  1. Rewrite all getStaticProps into fetch calls inside Suspense boundaries
  2. Convert Redux actions to React Query mutations
  3. ????
  4. Profit

But step 2 stalled when authentication headers stopped passing correctly. Turns out our middleware was hoisting the auth token from cookies in the React Query client—until it wasn’t. I debugged for 4 hours before realizing: the client had a useEffect in a layout component that wiped the auth state when navigating between pages. Solution? Move token refresh logic into the query client itself. Not glamorous, but worked.

Arabic language support bites back

Half the client’s users are Arabic speakers in the GCC. We’d implemented Next.js static i18n for the Pages Router, which fought the App Router’s new default app localization patterns. Dates in the booking flow started misformatting in Arabic locales because the App Router’s layout segments didn’t inherit locale contexts automatically. My workaround: a custom hook that force-sets the html[lang] attribute before any content renders. It’s not perfect, but no one’s complaining about Hijri calendar bugs (yet).

One thing I messed up

Rewriting all components as Server Components too early. I got excited about the SEO gains, converted 20 UI elements into 'use client' components, then realized we needed dynamic animations in the limo selection view. Had to backtrack and split components into Client and Server pieces. Learned that lesson the hard way.

Performance wins

After shipping the migration, metrics improved:

  • Initial page loads dropped from 2.3s to 1.1s on mobile
  • Bundle size cut by 40% through Turbopack (though I still distrust its caching)
  • Our SEO audit score jumped from 68 to 92, mostly from better meta tag controls in layout.tsx

The client didn’t notice any of this. They just said “Google Ads approvals came through finally” and stopped blocking my budget requests for AI integrations.

Gulf market context

Working in the UAE means deadlines often bend around Ramadan or major events. This time it was World Cup sponsorships, but last month I had to pause a React Native project for a client who suddenly needed everything translated for UAE National Day. The App Router migration’s timing wasn’t random—it had to launch before the World Cup crowds hit Dubai roads.

Would I do it again? Hell yes. But I’d prep the team with better testing for locale issues and slower rollouts. Also, the part where my teammate asked “are Server Components worth it?” the day we shipped with zero bugs? Yeah, that felt earned.

You can see the live result at tawasul.ae if you ever need a midnight ride from Jumeirah to a rooftop bar (a shockingly common use case here).

METADATA:{"excerpt":"Migrating Tawasul Limo's Next.js app to the App Router cut load times by 50%—and taught me about surviving UAE project deadlines.","tags":["nextjs","approuter","migration","uae","developer"]}"

S

Sarah

Senior Full-Stack Developer & PMP-Certified Project Lead — Abu Dhabi, UAE

7+ years building web applications for UAE & GCC businesses. Specialising in Laravel, Next.js, and Arabic RTL development.

Work with Sarah