Back to Blog
    Web Development

    Next.js 15: App Router, Server Actions, Turbopack & Everything New — Complete Guide

    Mortex Solutions TeamFebruary 18, 202616 min read
    Next.js 15: App Router, Server Actions, Turbopack & Everything New — Complete Guide

    Next.js 15 represents a major leap in the React meta-framework ecosystem, with Turbopack now stable for development, a completely reworked caching model, and Partial Prerendering bringing the best of static and dynamic rendering together.

    Next.js development environment

    🚀 What's New in Next.js 15

    • Turbopack (Stable) — Up to 76% faster local dev startup and 96% faster HMR
    • Partial Prerendering (PPR) — Mix static and dynamic content in a single route
    • Improved Caching — fetch requests and GET route handlers are no longer cached by default
    • React 19 Support — Full integration with React 19 features
    • next/after — Execute code after a response finishes streaming

    1. Turbopack — Blazing Fast Development

    Turbopack is now the default dev bundler. No config changes needed — just run next dev and enjoy the speed.

    # Turbopack is now default in Next.js 15
    next dev
    
    # Benchmarks (large app with 5000+ modules):
    # Cold start: 3.4s → 0.8s (76% faster)
    # HMR: 350ms → 15ms (96% faster)
    # Route compilation: 1.2s → 0.2s

    2. Partial Prerendering (PPR)

    PPR allows a single route to have both static and dynamic parts. The static shell is served instantly from the CDN, while dynamic content streams in via Suspense.

    // app/product/[id]/page.tsx
    import { Suspense } from 'react';
    
    // Enable PPR for this route
    export const experimental_ppr = true;
    
    // This part is static (prerendered at build time)
    export default async function ProductPage({ params }) {
      const product = await getProduct(params.id);
    
      return (
        <div>
          <h1>{product.name}</h1>
          <p>{product.description}</p>
    
          {/* This part is dynamic (streamed on each request) */}
          <Suspense fallback={<PriceSkeleton />}>
            <LivePrice productId={params.id} />
          </Suspense>
    
          <Suspense fallback={<ReviewsSkeleton />}>
            <CustomerReviews productId={params.id} />
          </Suspense>
        </div>
      );
    }

    3. Enhanced Server Actions

    Server Actions in Next.js 15 have improved error handling, better TypeScript inference, and support for revalidation.

    // app/actions.ts
    'use server';
    
    import { revalidatePath } from 'next/cache';
    import { redirect } from 'next/navigation';
    
    export async function createPost(formData: FormData) {
      const title = formData.get('title') as string;
      const content = formData.get('content') as string;
    
      // Validate
      if (!title || title.length < 3) {
        return { error: 'Title must be at least 3 characters' };
      }
    
      // Insert into database
      const post = await db.post.create({
        data: { title, content, publishedAt: new Date() }
      });
    
      // Revalidate the blog listing page
      revalidatePath('/blog');
    
      // Redirect to the new post
      redirect(`/blog/${post.slug}`);
    }
    
    // app/new-post/page.tsx
    import { createPost } from './actions';
    
    export default function NewPostPage() {
      return (
        <form action={createPost}>
          <input name="title" placeholder="Post title" required />
          <textarea name="content" placeholder="Write your post..." />
          <button type="submit">Publish</button>
        </form>
      );
    }

    4. next/after — Post-Response Tasks

    Run code after the response has been sent to the user — perfect for logging, analytics, and cache warming.

    import { after } from 'next/server';
    
    export async function POST(request: Request) {
      const data = await request.json();
      const result = await processOrder(data);
    
      // This runs AFTER the response is sent
      after(async () => {
        await sendConfirmationEmail(data.email);
        await updateAnalytics('order_placed', data);
        await warmCache(`/orders/${result.id}`);
      });
    
      return Response.json(result);
    }

    5. Caching Changes

    Next.js 15 no longer caches fetch requests by default — you must explicitly opt in. This makes the behaviour more predictable.

    // Next.js 14 — cached by default
    fetch('https://api.example.com/data');
    
    // Next.js 15 — NOT cached by default
    fetch('https://api.example.com/data');
    
    // Explicitly opt into caching
    fetch('https://api.example.com/data', {
      cache: 'force-cache'    // Cache indefinitely
    });
    
    fetch('https://api.example.com/data', {
      next: { revalidate: 60 } // Revalidate every 60 seconds
    });
    💡 Key Takeaway: Next.js 15 makes the framework faster (Turbopack), more predictable (caching changes), and more powerful (PPR + after). If you're starting a new project, Next.js 15 is the most capable full-stack React framework available.