본문으로 건너뛰기
Previous
Next
Next.js 15 Complete Guide | Turbopack· React 19

Next.js 15 Complete Guide | Turbopack· React 19

Next.js 15 Complete Guide | Turbopack· React 19

이 글의 핵심

Next.js 15 ships stable Turbopack (76% faster dev server), React 19 support, Partial Prerendering for hybrid static+dynamic pages, and important breaking changes to caching defaults. This guide covers every change with migration examples.

What’s New in Next.js 15

Next.js 15, released October 2024, marks a significant milestone with Turbopack reaching stability and major changes to how caching works. This release focuses on developer experience (faster dev server, better debugging) and aligning defaults with real-world usage patterns (most developers want fresh data by default, not aggressive caching).

If you’re upgrading from Next.js 14, the biggest impact is the fetch caching change ??requests that were cached automatically now need explicit cache configuration if you want caching. This is a breaking change that affects any app using fetch() for data fetching. Read the “Breaking Change: Fetch Caching Defaults” section below carefully before upgrading production apps.

Next.js 14 ??15 key changes:
  ??Turbopack stable for dev (76% faster startup, 96% faster HMR)
  ??React 19 support (optional, React 18 still works)
  ??Partial Prerendering (experimental) ??static + dynamic in one route
  ?�️ fetch() no longer cached by default (breaking!)
  ?�️ GET Route Handlers no longer cached by default
  ?�️ Client Router Cache no longer stale by default
  ??unstable_after() ??run analytics/logging after response sent
  ??Improved error UI with source maps in browser
  ??next.config.ts (TypeScript support, autocomplete)

Who Should Upgrade?

  • New projects: Use Next.js 15 from the start (benefits of Turbopack + modern defaults)
  • Existing projects: Upgrade if you want faster dev, but budget time for fetch() migration
  • Production apps: Test thoroughly ??caching behavior changed significantly

Upgrade

npx @next/upgrade latest
# Or manually:
npm install next@latest react@latest react-dom@latest
npm install -D @types/react@latest @types/react-dom@latest

Turbopack Dev Server

# Next.js 15: Turbopack is now the default for next dev
next dev

# Explicitly use Turbopack (same as default)
next dev --turbo

# Use webpack (opt-out)
next dev --no-turbo

Performance vs webpack:

MetricwebpackTurbopack
Server startupbaseline76% faster
Code updates (HMR)baseline96% faster
Large app cold start~15-60s~2-5s

Turbopack uses Rust-based incremental bundling ??only recompiles what changed.


Breaking Change: Fetch Caching Defaults

The biggest breaking change in Next.js 15:

// Next.js 14 default behavior
fetch('https://api.example.com/data')
// Equivalent to: cache: 'force-cache' (cached indefinitely)

// Next.js 15 default behavior
fetch('https://api.example.com/data')
// Equivalent to: cache: 'no-store' (NOT cached, fetches fresh every request)

Migration ??be explicit:

// Static (cached, like Next.js 14 behavior)
fetch('https://api.example.com/data', {
  cache: 'force-cache',
});

// ISR (cached with revalidation)
fetch('https://api.example.com/data', {
  next: { revalidate: 3600 },  // Revalidate every hour
});

// Dynamic (uncached ??same as new default)
fetch('https://api.example.com/data', {
  cache: 'no-store',
});

Similarly for Route Handlers:

// Next.js 14: GET handlers cached by default
// Next.js 15: GET handlers NOT cached by default

// app/api/products/route.ts
// To restore caching:
export const dynamic = 'force-static';
// Or:
export const revalidate = 3600;

Partial Prerendering (PPR)

PPR enables a single route to be both static and dynamic simultaneously:

// next.config.ts
import type { NextConfig } from 'next';

const config: NextConfig = {
  experimental: {
    ppr: 'incremental',  // Enable per-route, not globally
  },
};

export default config;
// app/product/[id]/page.tsx
export const experimental_ppr = true;  // Enable PPR for this route

import { Suspense } from 'react';

// Static shell ??rendered at build time, instant
export default function ProductPage({ params }: { params: { id: string } }) {
  return (
    <main>
      <StaticHeader />      {/* Rendered at build time */}
      <StaticNav />         {/* Rendered at build time */}

      {/* Dynamic content ??streamed at request time */}
      <Suspense fallback={<ProductSkeleton />}>
        <ProductDetails id={params.id} />   {/* Fetches from DB at request time */}
      </Suspense>

      <Suspense fallback={<ReviewsSkeleton />}>
        <PersonalizedRecommendations />     {/* Uses cookies/user data */}
      </Suspense>
    </main>
  );
}
PPR rendering flow:
  1. Build time:  Static shell generated (header, nav, skeletons)
  2. Request:     Shell served immediately from CDN (fast TTFB)
  3. Streaming:   Dynamic content streamed as data loads

React 19 Features in Next.js 15

use() Hook for Promises

'use client';
import { use, Suspense } from 'react';

// Pass a Promise to a Client Component
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
  const user = use(userPromise);  // Suspends until resolved
  return <div>{user.name}</div>;
}

// Server Component creates the promise
async function Page() {
  const userPromise = getUser(1);  // Don't await ??pass the promise

  return (
    <Suspense fallback={<Skeleton />}>
      <UserProfile userPromise={userPromise} />
    </Suspense>
  );
}

Improved useFormStatus

'use client';
import { useFormStatus } from 'react-dom';

function SubmitButton() {
  const { pending, data, method, action } = useFormStatus();

  return (
    <button disabled={pending} type="submit">
      {pending ? 'Saving...' : 'Save'}
    </button>
  );
}

Server Actions Improvements

// Optimistic updates with useOptimistic (React 19)
'use client';
import { useOptimistic } from 'react';
import { toggleLike } from './actions';

function LikeButton({ post }: { post: Post }) {
  const [optimisticLiked, setOptimisticLiked] = useOptimistic(post.liked);

  async function handleLike() {
    setOptimisticLiked(!optimisticLiked);  // Update UI immediately
    await toggleLike(post.id);             // Then sync with server
  }

  return (
    <button onClick={handleLike}>
      {optimisticLiked ? '?�️' : '?��'}
    </button>
  );
}

unstable_after ??Run Code After Response

Run cleanup/logging after the response is sent to the user ??without blocking the response:

// app/api/products/route.ts
import { unstable_after as after } from 'next/server';

export async function GET(request: Request) {
  const products = await getProducts();

  // Schedule this to run after response is sent
  after(async () => {
    await logRequest({
      path: '/api/products',
      duration: Date.now() - start,
      cached: false,
    });
    await updateAnalytics('product_list_viewed');
  });

  return Response.json(products);
}

next.config.ts ??TypeScript Config

// next.config.ts (new in Next.js 15 ??TypeScript support!)
import type { NextConfig } from 'next';

const config: NextConfig = {
  experimental: {
    ppr: 'incremental',
    reactCompiler: true,           // React Compiler (experimental)
  },

  images: {
    remotePatterns: [
      { protocol: 'https', hostname: 'cdn.example.com' },
    ],
  },

  // Moved from next.config.js ??fully typed
  headers: async () => [
    {
      source: '/api/:path*',
      headers: [
        { key: 'Access-Control-Allow-Origin', value: '*' },
      ],
    },
  ],
};

export default config;

Async Request APIs (Breaking Change)

Headers, cookies, and params are now async in Next.js 15:

// Next.js 14
import { cookies, headers } from 'next/headers';
const cookieStore = cookies();
const headersList = headers();

// Next.js 15 ??must await
import { cookies, headers } from 'next/headers';
const cookieStore = await cookies();
const headersList = await headers();

// Route params are also async
// Next.js 14
export default function Page({ params }: { params: { id: string } }) {
  console.log(params.id);
}

// Next.js 15
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  console.log(id);
}

Improved Error UI

Next.js 15 includes a redesigned error overlay in development:

  • Source maps now point to original TypeScript source (not compiled JS)
  • Error frames are collapsible
  • Better hydration error messages with diffs showing what changed
  • Next.js-specific errors link directly to relevant docs

Migration Checklist: Next.js 14 ??15

# 1. Upgrade
npx @next/upgrade latest

# 2. Check codemod for automated fixes
npx @next/codemod@canary upgrade latest

Manual checks:

  • fetch() calls ??add explicit cache: 'force-cache' where you relied on default caching
  • GET Route Handlers ??add export const dynamic = 'force-static' if they should be cached
  • cookies(), headers() ??add await
  • params and searchParams props ??add await (they’re now Promises)
  • next.config.js ??optionally rename to next.config.ts
  • Test all pages that rely on cached data

Related posts:

  • [Next.js App Router Rendering Guide](/en/blog/nextjs-app-router-rendering-strategies/
  • [React 18 Deep Dive](/en/blog/react-18-deep-dive/
  • [TypeScript 5 Complete Guide](/en/blog/typescript-5-complete-guide/

?�주 묻는 질문 (FAQ)

Q. ???�용???�무?�서 ?�제 ?�나??

A. Complete guide to Next.js 15 Complete Guide | Turbopack, React 19, Partial Prerendering & New APIs. Learn with practical???�무?�서????본문???�제?� ?�택 가?�드�?참고???�용?�면 ?�니??

Q. ?�행?�로 ?�으�?좋�? 글?�?

A. �?글 ?�단???�전 글 ?�는 관??글 링크�??�라가�??�서?��?배울 ???�습?�다. C++ ?�리�?목차?�서 ?�체 ?�름???�인?????�습?�다.

Q. ??깊이 공�??�려�?

A. cppreference?� ?�당 ?�이브러�?공식 문서�?참고?�세?? 글 말�???참고 ?�료 링크???�용?�면 좋습?�다.


같이 보면 좋�? 글 (?��? 링크)

??주제?� ?�결?�는 ?�른 글?�니??


??글?�서 ?�루???�워??(관??검?�어)

Next.js, Next.js 15, React 19, Turbopack, PPR, Frontend, TypeScript ?�으�?검?�하?�면 ??글???��????�니??