Advanced Next.js: Building Scalable Applications

# Advanced Next.js: Building Scalable Applications

This article explores advanced patterns and techniques for building large-scale applications with Next.js.

## Advanced Routing Patterns

### Parallel Routes

“`typescript

// app/@modal/login/page.tsx

export default function LoginModal() {

 return (

  <div className=”modal”>

   <h2>Login</h2>

   <form>

    {/* Login form fields */}

   </form>

  </div>

 );

}

// app/layout.tsx

export default function RootLayout({

 children,

 modal,

}: {

 children: React.ReactNode;

 modal: React.ReactNode;

}) {

 return (

  <html>

   <body>

    {children}

    {modal}

   </body>

  </html>

 );

}

“`

### Intercepting Routes

“`typescript

// app/posts/[id]/@modal/(.)edit/page.tsx

export default function EditPostModal({

 params,

}: {

 params: { id: string };

}) {

 return (

  <div className=”modal”>

   <h2>Edit Post {params.id}</h2>

   <PostForm id={params.id} />

  </div>

 );

}

“`

## Advanced State Management

### Server Actions with Optimistic Updates

“`typescript

‘use client’;

import { experimental_useOptimistic as useOptimistic } from ‘react’;

export default function TodoList({ initialTodos }) {

 const [optimisticTodos, addOptimisticTodo] = useOptimistic(

  initialTodos,

  (state, newTodo) => […state, newTodo]

 );

 async function addTodo(formData: FormData) {

  const todo = {

   id: Math.random(),

   text: formData.get(‘todo’),

   completed: false,

  };

  addOptimisticTodo(todo);

  await fetch(‘/api/todos’, {

   method: ‘POST’,

   body: JSON.stringify(todo),

  });

 }

 return (

  <div>

   <form action={addTodo}>

    <input name=”todo” />

    <button type=”submit”>Add Todo</button>

   </form>

   <ul>

    {optimisticTodos.map((todo) => (

     <li key={todo.id}>{todo.text}</li>

    ))}

   </ul>

  </div>

 );

}

“`

## Advanced Data Fetching

### Streaming with Suspense

“`typescript

// app/posts/page.tsx

import { Suspense } from ‘react’;

import PostList from ‘./PostList’;

import SkeletonList from ‘./SkeletonList’;

export default function PostsPage() {

 return (

  <div>

   <h1>Posts</h1>

   <Suspense fallback={<SkeletonList />}>

    <PostList />

   </Suspense>

  </div>

 );

}

// app/posts/PostList.tsx

async function PostList() {

 const posts = await fetchPostsSlowly();

  

 return (

  <ul>

   {posts.map((post) => (

    <li key={post.id}>{post.title}</li>

   ))}

  </ul>

 );

}

“`

### Parallel Data Fetching

“`typescript

// utils/fetch.ts

async function fetchPosts() {

 const res = await fetch(‘https://api.example.com/posts’);

 return res.json();

}

async function fetchUser(id: string) {

 const res = await fetch(`https://api.example.com/users/${id}`);

 return res.json();

}

// app/dashboard/page.tsx

export default async function Dashboard() {

 const [posts, user] = await Promise.all([

  fetchPosts(),

  fetchUser(‘current’),

 ]);

 return (

  <div>

   <UserProfile user={user} />

   <PostList posts={posts} />

  </div>

 );

}

“`

## Custom Server-Side Rendering

### Dynamic Rendering Decisions

“`typescript

// app/posts/[id]/page.tsx

import { headers } from ‘next/headers’;

import { redirect } from ‘next/navigation’;

export default async function Post({

 params,

}: {

 params: { id: string };

}) {

 const headersList = headers();

 const userAgent = headersList.get(‘user-agent’);

  

 // Dynamic rendering decision

 if (userAgent?.includes(‘Googlebot’)) {

  // Render differently for search engines

  return <StaticPostVersion id={params.id} />;

 }

 // Regular rendering

 return <DynamicPostVersion id={params.id} />;

}

“`

## Advanced Caching Strategies

### Revalidation Patterns

“`typescript

// app/api/revalidate/route.ts

import { revalidatePath, revalidateTag } from ‘next/cache’;

import { NextResponse } from ‘next/server’;

export async function POST(request: Request) {

 const { path, tag } = await request.json();

  

 if (path) {

  revalidatePath(path);

 }

  

 if (tag) {

  revalidateTag(tag);

 }

  

 return NextResponse.json({ revalidated: true });

}

// Usage in data fetching

fetch(‘https://api.example.com/posts’, {

 next: {

  tags: [‘posts’],

  revalidate: 3600,

 },

});

“`

## Performance Optimization

### Route Handlers Optimization

“`typescript

// app/api/posts/route.ts

import { NextResponse } from ‘next/server’;

import { headers } from ‘next/headers’;

export async function GET(request: Request) {

 const headersList = headers();

 const referer = headersList.get(‘referer’);

  

 // Cache configuration

 const cacheOptions = {

  headers: {

   ‘Cache-Control’: ‘public, s-maxage=10, stale-while-revalidate=59’,

  },

 };

  

 try {

  const posts = await fetchPosts();

  return NextResponse.json(posts, cacheOptions);

 } catch (error) {

  return NextResponse.json(

   { error: ‘Failed to fetch posts’ },

   { status: 500 }

  );

 }

}

“`

### Image Optimization Patterns

“`typescript

// components/OptimizedImage.tsx

import Image from ‘next/image’;

export default function OptimizedImage({

 src,

 alt,

}: {

 src: string;

 alt: string;

}) {

 return (

  <div className=”aspect-w-16 aspect-h-9 relative”>

   <Image

    src={src}

    alt={alt}

    fill

    sizes=”(max-width: 768px) 100vw,

        (max-width: 1200px) 50vw,

        33vw”

    className=”object-cover”

    loading=”lazy”

   />

  </div>

 );

}

“`

This article covers advanced Next.js topics, providing developers with sophisticated patterns for building scalable applications.

Would you like me to explain any specific aspect in more detail or cover additional advanced topics?

Leave a comment

Your email address will not be published. Required fields are marked *