Next.js App Router: My Real Experience With The Routing Revolution

Next.js App Router: My Real Experience With The Routing Revolution

An honest deep-dive into the Next.js App Router after months of actually using it in production. What works, what doesn't, and whether you should migrate your existing apps.

Raul Lugo

Next.js App Router: Worth The Hype or Just More JavaScript Churn?

Look, I'll be honest. When Vercel announced the App Router, my first reaction was "oh great, another framework rewrite I need to learn." I'd just gotten comfortable with the Pages Router, had a mental model that actually made sense, and suddenly there's this whole new paradigm to wrap my head around.

But after spending the last six months building production apps with it (and yes, dealing with the inevitable bugs and gotchas), I've got some thoughts.

What Actually Is This Thing?

The App Router is basically Next.js saying "we're going all-in on React Server Components." If you've been living under a rock, Server Components let you write components that run exclusively on the server, which means you can do database queries, access file systems, whatever, directly in your components without spinning up API routes.

Here's the simplest possible example:

// app/users/page.tsx
async function UsersPage() {
  const users = await db.query('SELECT * FROM users');
  
  return (
    <div>
      {users.map(user => (
        <div key={user.id}>{user.name}</div>
      ))}
    </div>
  );
}

export default UsersPage;

That's it. No getServerSideProps, no API route, no fetching on the client. Just... query the database in your component. When I first saw this, I thought "this feels wrong" because we've been trained for years that components are pure UI. But honestly? After using it, I'm kind of sold.

Why They Built It (And Why The Pages Router Was Holding Them Back)

The Pages Router worked great when Next.js apps were simpler. But as someone who's built a couple massive Next.js apps (think 200+ pages, complex data flows), the cracks started showing.

The biggest issue? Everything was either fully server-rendered OR fully client-rendered. You couldn't granularly control which parts of your page needed JavaScript and which didn't. Your entire page was wrapped in getServerSideProps or your entire page was a client component. No middle ground.

The App Router fixes this with Server Components, but it also adds streaming. And streaming is where things get really interesting.

// app/dashboard/page.tsx
import { Suspense } from 'react';

async function SlowDataComponent() {
  const data = await fetchSlowAPI(); // Takes 3 seconds
  return <div>{data}</div>;
}

function DashboardPage() {
  return (
    <div>
      <h1>Dashboard</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <SlowDataComponent />
      </Suspense>
    </div>
  );
}

The page shell loads instantly, and the slow part streams in when it's ready. Your users don't stare at a blank screen. This alone makes the App Router worth considering.

The Good Stuff (What I Actually Like)

Performance That Actually Matters

I'm not talking about Lighthouse scores (though those improved too). I'm talking about real user experience. One of my production apps went from a 2.3s Time to First Byte to 800ms just by migrating to the App Router and using Server Components properly. That's not a typo.

The reason? We were making a bunch of sequential API calls in getServerSideProps, blocking the entire page render. With Server Components and Suspense, those calls happen in parallel and stream in independently. Game changer.

Incremental Adoption (Thank God)

Here's something Vercel actually got right: you don't have to rewrite your entire app overnight. You can have both the Pages Router and App Router running side by side. Your old pages keep working in the pages/ directory while you build new stuff in app/.

I've been migrating one of my apps gradually over the last three months. It's been surprisingly painless. Well, mostly painless. More on that later.

Layouts That Don't Re-render

This one's subtle but huge. In the Pages Router, if you wanted a persistent layout (say, a sidebar that doesn't re-mount between page navigations), you had to do weird stuff with custom _app.js components and state management.

// app/layout.tsx
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Sidebar /> {/* This persists across navigations */}
        {children}
      </body>
    </html>
  );
}

In the App Router, layouts are first-class. They don't re-render when you navigate between pages. Your sidebar state, your modals, everything just... stays. It feels like a SPA should feel.

The Frustrating Parts (Because It's Not All Roses)

The Learning Curve Is Real

I'm not gonna sugarcoat this: if you're comfortable with the Pages Router, the App Router will feel alien at first. The mental model is completely different. You need to understand Server Components vs Client Components, when to use "use client", how data fetching works, how caching works (oh god, the caching).

I spent two weeks scratching my head over why my data wasn't updating, only to discover Next.js aggressively caches everything by default. You have to explicitly opt out:

// This is cached by default
const data = await fetch('https://api.example.com/data');

// This opts out of caching
const data = await fetch('https://api.example.com/data', {
  cache: 'no-store'
});

That's... not intuitive. And the docs don't make it super clear when you're hitting cache vs making fresh requests.

The Ecosystem Isn't Quite There Yet

A lot of libraries assume client-side rendering. When I tried to use some UI libraries with Server Components, things broke in weird ways. You end up wrapping a lot of stuff in "use client" directives, which kind of defeats the purpose.

And don't get me started on testing. Most testing libraries are built for client components. Testing Server Components is still a bit of a Wild West situation.

Stability Took A While

When I first started using the App Router (around Next.js 13.2), there were bugs. Random hydration errors, weird caching issues, stuff that worked in dev but broke in production. To Vercel's credit, they've been shipping fixes aggressively. By 13.4, it felt production-ready. But those early months were rough.

If you're migrating a critical production app, I'd honestly wait until you're on at least Next.js 13.4 or later.

Should You Actually Migrate?

Here's my honest take: it depends.

Migrate if:

  • You're building a new app from scratch (just start with App Router)
  • Your app has complex data fetching needs
  • You care about streaming and progressive rendering
  • You've got time to learn a new paradigm

Stick with Pages Router if:

  • Your current app works fine and you don't have performance issues
  • You're on a tight deadline and can't afford the learning curve
  • You're using libraries that don't play nice with Server Components yet
  • You just don't want to deal with another framework churn cycle (valid)

For me personally? I'm all-in on the App Router for new projects. For existing apps, I'm migrating gradually as I touch different parts of the codebase. No rush.

The Documentation Situation

I've gotta call this out: the Next.js docs are actually pretty good now. They completely rewrote them when they launched the App Router, and there's a solid migration guide.

That said, a lot of the edge cases aren't well-documented. I've spent more time than I'd like digging through GitHub issues to figure out why something isn't working. The community on Discord has been helpful, but it would be nice if this stuff was just in the docs.

Real Talk: Is This The Future?

Yeah, I think so. React Server Components are clearly the direction React is headed, and Next.js is betting the farm on it. Whether you love it or hate it, this is where the ecosystem is going.

I was skeptical at first (and honestly, I'm still not convinced about everything the React team is doing), but after using Server Components in production, I get it. The ability to collocate your data fetching with your UI, eliminate waterfalls, and reduce JavaScript sent to the client... it's compelling.

Plus, Remix and other frameworks are moving in similar directions. This isn't just a Next.js thing anymore.

Final Thoughts

The App Router is powerful but opinionated. It forces you to think differently about how you structure your apps. Some days I love it. Some days I miss the simplicity of just throwing everything in getServerSideProps and calling it a day.

But here's the thing: the web is getting more complex, and our tools need to evolve. The App Router handles that complexity better than the Pages Router ever could. It's not perfect, and it's definitely not for everyone, but it's a solid step forward.

If you want to dive deeper, check out the official Next.js blog post and actually build something with it. Don't just read about it. That's the only way it'll click.

Now if you'll excuse me, I've got some hydration errors to debug.