Advanced Routing Techniques in Next.js

Next.js 13+ introduced revolutionary changes to routing with the App Router. In this comprehensive guide, we'll explore advanced routing techniques that will help you build more sophisticated and maintainable Next.js applications. Table of Contents Understanding the App Router Dynamic Routes and Segments Parallel and Intercepting Routes Route Groups and Organization Loading and Error States Route Handlers (API Routes) Middleware and Protected Routes Understanding the App Router The App Router works on the convention of using directories for routing. Here's the basic structure: app/ ├── page.tsx // Home route (/) ├── about/ │ └── page.tsx // About route (/about) ├── blog/ │ └── page.tsx // Blog route (/blog) │ └── [slug]/ │ └── page.tsx // Individual blog post (/blog/post-1) Dynamic Routes and Segments Dynamic Segments Dynamic segments allow you to create routes with parameters. Here's how to implement them: // app/blog/[slug]/page.tsx export default async function BlogPost({ params }: { params: { slug: string } }) { return ( Blog Post: {params.slug} ); } // Generate static params for static generation export async function generateStaticParams() { const posts = await fetchPosts(); return posts.map((post) => ({ slug: post.slug, })); } Catch-all Segments For handling multiple dynamic segments: // app/docs/[...slug]/page.tsx export default function DocsPage({ params }: { params: { slug: string[] } }) { // slug will be an array: /docs/a/b/c → ['a', 'b', 'c'] return ( Documentation Current path: {params.slug.join('/')} ); } Parallel and Intercepting Routes Parallel Routes Parallel routes allow you to simultaneously render multiple pages in the same layout: // app/@modal/login/page.tsx export default function LoginModal() { return ( Login {/* Login form */} ); } // app/layout.tsx export default function Layout(props: { children: React.ReactNode; modal: React.ReactNode; }) { return ( {props.children} {props.modal} ); } Intercepting Routes Intercepting routes let you show a route while preserving the context of the current page: // app/photos/[...slug]/(..)gallery/page.tsx // This will intercept /photos/gallery while showing /photos/[slug] export default function GalleryModal() { return ( Photo Gallery {/* Gallery content */} ); } Route Groups and Organization Route groups help organize your routes without affecting the URL structure: app/ ├── (marketing) │ ├── about/ │ ├── blog/ │ └── layout.tsx ├── (shop) │ ├── products/ │ ├── cart/ │ └── layout.tsx └── layout.tsx Loading and Error States Implement loading and error states for better user experience: // app/products/loading.tsx export default function Loading() { return ( Loading... ); } // app/products/error.tsx 'use client'; export default function Error({ error, reset, }: { error: Error; reset: () => void; }) { return ( Something went wrong! reset()}>Try again ); } Route Handlers (API Routes) Create API endpoints using Route Handlers: // app/api/posts/route.ts import { NextResponse } from 'next/server'; export async function GET() { const posts = await fetchPosts(); return NextResponse.json(posts); } export async function POST(request: Request) { const data = await request.json(); const newPost = await createPost(data); return NextResponse.json(newPost, { status: 201 }); } Middleware and Protected Routes Implement route protection using middleware: // middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export function middleware(request: NextRequest) { const token = request.cookies.get('auth-token'); if (!token && request.nextUrl.pathname.startsWith('/dashboard')) { return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); } export const config = { matcher: ['/dashboard/:path*', '/api/:path*'], }; Best Practices and Tips Keep Routes Organized: Use route groups to maintain a clean project structure Implement Error Boundaries: Always handle errors gracefully Use Loading States: Provide feedback during data fetching Type Safety: Leverage TypeScript for better type safety Caching Strategy: Implement proper caching strategies using Next.js built-in caching mechanisms Conclusion Next.js's App Router provides powerful routing capabilities that can help you build complex applications with ease. By understanding and implementing these advanced routing techniques, you can create more maintainable and user-friendly applications. Remember to: Plan your route structure car

Feb 22, 2025 - 09:29
 0
Advanced Routing Techniques in Next.js

Next.js 13+ introduced revolutionary changes to routing with the App Router. In this comprehensive guide, we'll explore advanced routing techniques that will help you build more sophisticated and maintainable Next.js applications.

Table of Contents

  1. Understanding the App Router
  2. Dynamic Routes and Segments
  3. Parallel and Intercepting Routes
  4. Route Groups and Organization
  5. Loading and Error States
  6. Route Handlers (API Routes)
  7. Middleware and Protected Routes

Understanding the App Router

The App Router works on the convention of using directories for routing. Here's the basic structure:

app/
├── page.tsx          // Home route (/)
├── about/
   └── page.tsx      // About route (/about)
├── blog/
   └── page.tsx      // Blog route (/blog)
   └── [slug]/
       └── page.tsx  // Individual blog post (/blog/post-1)

Dynamic Routes and Segments

Dynamic Segments

Dynamic segments allow you to create routes with parameters. Here's how to implement them:

// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }: { params: { slug: string } }) {
  return (
    <article>
      <h1>Blog Post: {params.slug}</h1>
    </article>
  );
}

// Generate static params for static generation
export async function generateStaticParams() {
  const posts = await fetchPosts();

  return posts.map((post) => ({
    slug: post.slug,
  }));
}

Catch-all Segments

For handling multiple dynamic segments:

// app/docs/[...slug]/page.tsx
export default function DocsPage({ params }: { params: { slug: string[] } }) {
  // slug will be an array: /docs/a/b/c → ['a', 'b', 'c']
  return (
    <div>
      <h1>Documentation</h1>
      <p>Current path: {params.slug.join('/')}</p>
    </div>
  );
}

Parallel and Intercepting Routes

Parallel Routes

Parallel routes allow you to simultaneously render multiple pages in the same layout:

// app/@modal/login/page.tsx
export default function LoginModal() {
  return (
    <div className="modal">
      <h2>Login</h2>
      {/* Login form */}
    </div>
  );
}

// app/layout.tsx
export default function Layout(props: {
  children: React.ReactNode;
  modal: React.ReactNode;
}) {
  return (
    <div>
      {props.children}
      {props.modal}
    </div>
  );
}

Intercepting Routes

Intercepting routes let you show a route while preserving the context of the current page:

// app/photos/[...slug]/(..)gallery/page.tsx
// This will intercept /photos/gallery while showing /photos/[slug]
export default function GalleryModal() {
  return (
    <div className="modal">
      <h2>Photo Gallery</h2>
      {/* Gallery content */}
    </div>
  );
}

Route Groups and Organization

Route groups help organize your routes without affecting the URL structure:

app/
├── (marketing)
   ├── about/
   ├── blog/
   └── layout.tsx
├── (shop)
   ├── products/
   ├── cart/
   └── layout.tsx
└── layout.tsx

Loading and Error States

Implement loading and error states for better user experience:

// app/products/loading.tsx
export default function Loading() {
  return (
    <div className="loading-spinner">
      <span>Loading...</span>
    </div>
  );
}

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

export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <div className="error-container">
      <h2>Something went wrong!</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  );
}

Route Handlers (API Routes)

Create API endpoints using Route Handlers:

// app/api/posts/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  const posts = await fetchPosts();
  return NextResponse.json(posts);
}

export async function POST(request: Request) {
  const data = await request.json();
  const newPost = await createPost(data);
  return NextResponse.json(newPost, { status: 201 });
}

Middleware and Protected Routes

Implement route protection using middleware:

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const token = request.cookies.get('auth-token');

  if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/dashboard/:path*', '/api/:path*'],
};

Best Practices and Tips

  1. Keep Routes Organized: Use route groups to maintain a clean project structure
  2. Implement Error Boundaries: Always handle errors gracefully
  3. Use Loading States: Provide feedback during data fetching
  4. Type Safety: Leverage TypeScript for better type safety
  5. Caching Strategy: Implement proper caching strategies using Next.js built-in caching mechanisms

Conclusion

Next.js's App Router provides powerful routing capabilities that can help you build complex applications with ease. By understanding and implementing these advanced routing techniques, you can create more maintainable and user-friendly applications.

Remember to:

  • Plan your route structure carefully
  • Implement proper error handling
  • Use TypeScript for better type safety
  • Consider performance implications
  • Keep your code organized using route groups

For more information, refer to the official Next.js documentation.

Note: This blog post assumes you're using Next.js 13+ with the App Router. Some features might vary depending on your Next.js version.