Deep Diving into the Next.js App Router
Debajit Mallick

Debajit Mallick @debajit13

About: Senior Software Engineer @P360 | Frontend Developer👨‍💻 | Co-organizer @GDG Siliguri🚀 | Ex β-MLSA | Ex Hack Club Lead | Smart India Hackathon 2020 Winner & 2022 Mentor of Winner Team

Location:
Jalpaiguri, West Bengal, India
Joined:
Oct 3, 2019

Deep Diving into the Next.js App Router

Publish Date: Apr 2
0 0

Introduction

Let's be honest - Next.js has completely changed how we build React apps. With the release of Next.js 13 and the stabilization in version 14, the new App Router has turned everything I knew about routing on its head - and I'm loving it.

If you're just getting started with Next.js, this new approach takes some getting used to.

In this blog, we will talk about the App Router, how it actually works in practice, and some cool tricks you can use to leverage your app.

What is the App Router?

Instead of throwing everything into that /pages directory we've all grown familiar with, you now organize your app under /app. It might seem like a simple change, but it completely transforms how you think about your application structure.

The App Router isn't just about changing folders - it's about embracing React Server Components, streaming, and nested layouts in a way that actually makes sense in production.

Directory Structure: It's All About Conventions

Let me show you how I typically structure a project now:

/app
  /dashboard
    page.tsx        # This gives you /dashboard
    layout.tsx      # Shared UI wrapper that stays consistent
    loading.tsx     # That nice loading spinner users see
    error.tsx       # When things break (and they will)
  /profile
    page.tsx        # Your /profile route
layout.tsx          # The root layout wrapping everything
page.tsx            # Your homepage (/)
Enter fullscreen mode Exit fullscreen mode

The key files I work with daily:

  • page.tsx: This is the actual page content
  • layout.tsx: Where I put navigation, sidebars, and other persistent UI
  • template.tsx: Like layout but re-mounts between navigations (great for animations)
  • loading.tsx: My fallback UI when data is loading
  • error.tsx: Custom error handling per route (a lifesaver in production)

Layouts: Keep the Good Parts, Change the Rest

One thing I absolutely love about the App Router is how layouts work. In the old Pages Router, I'd have to wrap everything in a _app.tsx file and handle layout transitions manually.

Now, I just create layout files where needed:

// app/layout.tsx
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Navbar />
        <main>{children}</main>
      </body>
    </html>
  );
}
Enter fullscreen mode Exit fullscreen mode

The best part? The <Navbar /> stays put during navigation, with only the children updating. No more full-page refreshes or navbar flickers. Your users will thank you.

Server vs Client Components: The Mental Model That Took Me Weeks to Get Right

This was honestly the biggest hurdle for me. In the App Router, everything is a server component by default. That means your components run on the server unless you explicitly opt out.

When I need interactivity, I add the 'use client' directive:

'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Enter fullscreen mode Exit fullscreen mode

It took me a while to develop the right mental model here, but now I think: "Server component until proven interactive." This approach has drastically reduced the JavaScript I'm sending to my users.

Routing: From Simple to Complex in No Time

Basic routes are straightforward - create a folder, add a page.tsx file, and you're done:

app/about/page.tsx → /about
Enter fullscreen mode Exit fullscreen mode

But where things get interesting is with dynamic routes:

app/blog/[slug]/page.tsx → /blog/:slug
Enter fullscreen mode Exit fullscreen mode

I access the params like this:

export default function BlogPost({ params }) {
  return <h1>Post: {params.slug}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

Need to handle arbitrary depth? Catch-all routes have you covered:

app/docs/[...slug]/page.tsx → /docs/a/b/c
Enter fullscreen mode Exit fullscreen mode

I've also fallen in love with parallel routes (using @ folders) and intercepting routes (with the . prefix) for building modals that don't break deep linking. Game changer for complex UIs.

Loading States That Don't Make Users Wait

This is where the App Router truly shines. Instead of showing a blank screen or a full-page loader, I can now create targeted loading states:

// app/dashboard/loading.tsx
export default function Loading() {
  return <p>Loading dashboard data...</p>;
}
Enter fullscreen mode Exit fullscreen mode

Combined with React Suspense and streaming, my apps now feel instantly responsive even when data takes a second to load.

Error Handling That Doesn't Crash Your Entire App

We've all been there - one API call fails and your entire app shows the dreaded error page. With the App Router, I can isolate errors to specific routes:

// app/profile/error.tsx
'use client';

export default function Error({ error, reset }) {
  return (
    <div>
      <p>Sorry, we couldn't load your profile: {error.message}</p>
      <button onClick={() => reset()}>Try again</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

The rest of the app keeps working, and users can retry the failed operation. My support tickets have dropped dramatically since implementing this pattern.

API Routes: Simplified and Co-located

API routes have also gotten a makeover. Instead of the old /pages/api approach, I now use route handlers:

// app/api/hello/route.ts
export async function GET() {
  return Response.json({ message: 'Hello from API!' });
}
Enter fullscreen mode Exit fullscreen mode

I can export GET, POST, PUT, DELETE directly as functions, which feels much more intuitive than the old switch (req.method) pattern.

Conclusion

The App Router is clearly designed with modern applications in mind. It embraces server components, streaming, and composition in ways that make complex UIs manageable. Whether you're building a SaaS dashboard, an e-commerce site, or a content platform, the App Router gives you powerful tools that grow with your application. If you like this blog and want to learn more about Frontend Development and Software Engineering, you can follow me on Dev.to.

Comments 0 total

    Add comment