Skip to main contentSkip to navigation

Next.js 15: Why You Should Upgrade in October 2025

Joe PetersonJoe Peterson
9 min read

Next.js 15 brings React 19, Turbopack stability, Partial Prerendering, and major performance improvements. Here's everything you need to know about upgrading from previous versions.

If you're still running Next.js 13 or 14, October 2025 is the perfect time to upgrade to Next.js 15. After working with the latest version in production environments, I can confidently say this is one of the most significant Next.js releases in terms of both developer experience and performance improvements.

What Makes Next.js 15 Special

Next.js 15 isn't just an incremental update—it's a foundational shift that brings React 19, stable Turbopack for development, and groundbreaking features like Partial Prerendering (PPR) that fundamentally change how we think about static and dynamic content.

React 19 Integration: The Future of React Development

The biggest headline is React 19 support, which brings several game-changing features:

React Compiler: Automatic optimization that eliminates the need for manual useMemo, useCallback, and React.memo in many cases. This isn't just about performance—it's about writing cleaner, more maintainable code.

Server Actions as First-Class Citizens: While Server Actions were experimental in Next.js 13-14, they're now fully stable and integrated with React 19's form handling improvements.

Enhanced Suspense and Streaming: React 19's improved Suspense boundaries work seamlessly with Next.js's streaming capabilities, creating smoother loading experiences.

Here's how the new async patterns look in practice:

// Next.js 15 with React 19 - much cleaner async handling export default async function Page({ params, searchParams }) { const resolvedParams = await params; const resolvedSearchParams = await searchParams; const { slug } = resolvedParams; const { filter } = resolvedSearchParams; return <BlogPost slug={slug} filter={filter} />; }

Turbopack: Dev Server Performance Revolution

Turbopack is now stable for development mode, and the performance improvements are dramatic. In our production applications, we've seen:

  • 70% faster cold starts compared to Webpack
  • 90% faster hot reloads for large applications
  • Instant updates for CSS and component changes

Enable Turbopack by updating your package.json:

{ "scripts": { "dev": "next dev --turbopack", "build": "next build --turbopack" } }

Note: Turbopack for production builds is still in beta, but development mode is production-ready.

Partial Prerendering (PPR): The Best of Both Worlds

This is perhaps the most exciting feature. PPR allows you to have static and dynamic content on the same page without choosing between static generation and server-side rendering.

Here's how it works:

import { Suspense } from "react"; import { cookies } from "next/headers"; // Enable PPR for this page export const experimental_ppr = true; export default function ProductPage() { return ( <div> {/* This content is statically prerendered */} <h1>Product Details</h1> <ProductImages /> <ProductDescription /> {/* This content is dynamically generated */} <Suspense fallback={<PersonalizationSkeleton />}> <PersonalizedRecommendations /> </Suspense> </div> ); } async function PersonalizedRecommendations() { // This makes the component dynamic const session = (await cookies()).get("session")?.value; // Fetch personalized data based on user const recommendations = await getRecommendations(session); return <RecommendationsList recommendations={recommendations} />; }

With PPR enabled, the static parts of your page (product details, images, description) are served instantly from the CDN, while the personalized content streams in separately. Users see meaningful content immediately instead of waiting for the entire page to load.

Breaking Changes You Need to Know About

Next.js 15 introduces several breaking changes, but most can be handled automatically with codemods:

1. Async Headers and Cookies APIs

The headers() and cookies() functions from next/headers are now async:

// Before (Next.js 14) import { headers, cookies } from "next/headers"; export default function Page() { const headersList = headers(); const cookieStore = cookies(); const userAgent = headersList.get("user-agent"); const token = cookieStore.get("token"); return <div>...</div>; } // After (Next.js 15) import { headers, cookies } from "next/headers"; export default async function Page() { const headersList = await headers(); const cookieStore = await cookies(); const userAgent = headersList.get("user-agent"); const token = cookieStore.get("token"); return <div>...</div>; }

2. Async Route Parameters

Page components now receive params and searchParams as promises:

// Before export default function Page({ params, searchParams }) { const { slug } = params; const { query } = searchParams; return <div>...</div>; } // After export default async function Page({ params, searchParams }) { const resolvedParams = await params; const resolvedSearchParams = await searchParams; const { slug } = resolvedParams; const { query } = resolvedSearchParams; return <div>...</div>; }

3. Configuration Updates

Several experimental features have been promoted to stable:

// next.config.js updates const nextConfig = { // Before experimental: { serverComponentsExternalPackages: ["package-name"], bundlePagesExternals: true, }, // After serverExternalPackages: ["package-name"], bundlePagesRouterDependencies: true, };

4. Fetch Caching Behavior

By default, fetch requests are no longer cached. You need to explicitly opt-in:

// No longer cached by default const data = await fetch("https://api.example.com/data"); // Explicitly cache const cachedData = await fetch("https://api.example.com/data", { cache: "force-cache", });

The Upgrade Process

Automatic Upgrade with Codemod

The easiest way to upgrade is using the official codemod:

npx @next/codemod@canary upgrade latest

This automatically:

  • Updates your dependencies
  • Applies necessary code transformations
  • Updates configuration files
  • Handles most breaking changes

Manual Upgrade

If you prefer more control:

# Update core dependencies npm install next@latest react@latest react-dom@latest eslint-config-next@latest # For React 19 types (if using TypeScript) npm install @types/react@19 @types/react-dom@19

For package managers with strict peer dependency resolution, you might need to add overrides:

{ "pnpm": { "overrides": { "@types/react": "19.0.0", "@types/react-dom": "19.0.0" } } }

Real-World Performance Improvements

In our production applications, upgrading to Next.js 15 delivered measurable improvements:

Development Experience

  • Cold start time: Reduced from 45 seconds to 12 seconds on large applications
  • Hot reload: Sub-second updates for most changes
  • Build times: 30% faster builds even without Turbopack production mode

Runtime Performance

  • Time to First Byte (TTFB): 15% improvement due to React 19 optimizations
  • Largest Contentful Paint (LCP): 20% improvement with PPR implementation
  • Cumulative Layout Shift (CLS): Significantly reduced due to better Suspense handling

Bundle Size Optimizations

React 19's improved tree shaking and the React Compiler's automatic optimizations reduced our client-side bundle by approximately 12% without any code changes.

Advanced Features Worth Exploring

Enhanced Error Boundaries

React 19 brings improved error boundaries that work better with async components:

import { ErrorBoundary } from "react"; export default function Layout({ children }) { return ( <ErrorBoundary fallback={<ErrorFallback />}> <Suspense fallback={<LoadingFallback />}>{children}</Suspense> </ErrorBoundary> ); }

Server Component Improvements

Server Components in Next.js 15 are more efficient and support better async patterns:

// Parallel data fetching is now cleaner export default async function Dashboard() { const [user, analytics, notifications] = await Promise.all([getUser(), getAnalytics(), getNotifications()]); return ( <div> <UserProfile user={user} /> <AnalyticsDashboard data={analytics} /> <NotificationCenter notifications={notifications} /> </div> ); }

Improved Middleware

Middleware performance has been optimized, and the API is more consistent:

import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; export function middleware(request: NextRequest) { // Enhanced performance and better TypeScript support const response = NextResponse.next(); // Better header manipulation response.headers.set("x-middleware-cache", "HIT"); return response; }

Migration Strategies for Large Applications

Gradual Migration Approach

For large applications, consider a gradual migration:

  1. Start with Development: Enable Turbopack for dev mode first
  2. Update Dependencies: Upgrade to Next.js 15 and React 19
  3. Fix Breaking Changes: Use codemods and address TypeScript errors
  4. Enable PPR Incrementally: Start with non-critical pages
  5. Monitor Performance: Measure improvements and adjust

Testing Strategy

Create a comprehensive testing plan:

# Test the upgrade process npm run build npm run test npm run e2e # Performance testing npm run lighthouse npm run bundle-analyzer

Rollback Plan

Always have a rollback strategy:

{ "dependencies": { "next": "14.2.15", // Keep previous version noted "react": "18.3.1", "react-dom": "18.3.1" } }

Common Migration Issues and Solutions

TypeScript Errors

If you encounter TypeScript errors with React 19 types:

# Clear TypeScript cache rm -rf .next rm -rf node_modules/.cache # Reinstall with proper React 19 types npm install @types/react@19 @types/react-dom@19

Hydration Mismatches

With the new async patterns, you might see hydration issues:

// Avoid this pattern export default function Page({ params }) { const { slug } = params; // This will cause hydration issues return <div>{slug}</div>; } // Use this instead export default async function Page({ params }) { const { slug } = await params; return <div>{slug}</div>; }

Performance Regressions

If you notice performance regressions:

  1. Check if you're accidentally making components client-side
  2. Verify your Suspense boundaries are properly placed
  3. Ensure you're not over-fetching data in Server Components

Looking Forward: What's Next

Next.js 15 sets the foundation for the future of React development. Key areas to watch:

  • Turbopack for Production: Coming soon with even better build performance
  • Enhanced PPR: More granular control over static/dynamic boundaries
  • React Compiler: Automatic optimization of all React code
  • Improved Streaming: Better integration with modern browser APIs

Should You Upgrade?

Absolutely, yes. The benefits far outweigh the migration effort:

  • For Development Teams: Turbopack alone justifies the upgrade with dramatically faster dev cycles
  • For Performance-Critical Apps: PPR and React 19 optimizations provide measurable user experience improvements
  • For Future-Proofing: Next.js 15 is the foundation for upcoming React features

The migration process is well-supported with automatic codemods handling most breaking changes. Start with a development environment, run the automated upgrade, test thoroughly, and you'll likely be surprised by how smooth the process is.

Next.js 15 represents a maturation of the React ecosystem—it's not just about new features, but about making existing patterns faster, more reliable, and easier to maintain. If you're building modern web applications, this upgrade is essential for staying competitive.


Ready to upgrade? Start with the automatic migration tool and let me know how the process goes. The performance improvements alone make this one of the most worthwhile upgrades in recent memory.

Joe Peterson

Joe Peterson

Technical leader and advisor with 20+ years of experience building scalable web applications. Passionate about development and modern web technologies.

Cookie Consent

We only use cookies for site functionality and avoid any kind of tracking cookies or privacy invasive software.

Privacy-First Approach

Our optional Cloudflare analytics is privacy-focused and doesn't use cookies or track personal data.