Web Developmentnextjsreact

Next.js 15 - What's New?

By Johannes Hayer
Picture of the author
Published on

Next.js 15: A Comprehensive Overview

Table of Contents

Introduction

Next.js 15 brings significant improvements to development speed, caching behavior, and overall developer experience. Let's break down these exciting changes and see how they'll impact your development workflow. If you want to see the new changes in code, please have a look at my nextjs-15 repo where I have prepared those new changes for you: https://github.com/XamHans/nextjs-15-changes/tree/main/nextjs-15-changes

Breaking Changes

Async Request APIs: The New Standard

The most significant breaking change in Next.js 15 is the transition to asynchronous request APIs. This change affects how we handle:

  • Cookies
  • Headers
  • Draft mode
  • Parameters in various files
  • Search parameters

Previously, you could access these directly:

// Old way
const cookies = cookies()

// New way
const cookies = await cookies()

This change enables the server to prepare content before requests arrive, improving overall performance. To help with migration, Next.js provides the @next/codemod CLI tool for automatic code updates.

Revised Caching Behavior

Next.js 15 introduces two major changes to caching:

  1. GET Route Handlers: No longer cached by default

    • Previous versions cached automatically
    • Now requires explicit opt-in
    • Use export const dynamic = 'force-static' for caching
  2. Client Router Cache: Page components aren't cached by default

    • Default stale time is now zero
    • Layouts maintain previous caching behavior
    • JS files still cache for 5 minutes

To retain previous caching behavior, add this to your next.config.js:

module.exports = {
  experimental: {
    clientRouterCacheConfig: {
      default: {
        revalidate: false
      }
    }
  }
}

Developer Experience Improvements

Enhanced Error Handling

Hydration errors are now more developer-friendly:

  • Detailed error messages
  • Source code context
  • Actionable fix suggestions

Turbopack Stability

Turbopack reaches stability with impressive improvements:

  • 76.7% faster local server startup
  • 96.3% faster code updates
  • 45.8% faster initial route compilation

Enable it using:

next dev --turbo

Static Route Indicator

A new visual indicator during development shows whether routes are static or dynamic, helping developers optimize performance without diving into code.

Post-Response Code Execution

Next.js 15 introduces the ability to run code after sending responses to users:

import { unstable_after as after } from 'next/server'
 
export default function Page() {
  after(() => {
    // Analytics or logging code here
  })
  return <h1>Hello</h1>
}

Enable this feature in next.config.js:

experimental: {
  unstable_after: true
}

New Form Component

The new <Form> component brings several improvements:

  • Automatic layout prefetching
  • State preservation during submissions
  • Progressive enhancement support
  • Works without JavaScript
import { Form } from 'next/form'

export default function Page() {
  return (
    <Form action="/api/submit">
      {/* Form fields */}
    </Form>
  )
}

Instrumentation

Next.js 15 has stabilized the instrumentation feature, making it a robust solution for server monitoring and observability. The instrumentation.js (or instrumentation.ts) file now provides a stable API for integrating with the Next.js server lifecycle, offering powerful capabilities for monitoring, error tracking, and performance optimization.

Key Features

  1. Server Lifecycle Integration

    • Monitor server performance
    • Track error sources
    • Integrate with observability tools like OpenTelemetry
    • Initialize services during server startup
  2. Stable API

    • No longer requires experimental.instrumentationHook configuration
    • Simplified setup process
    • Reliable production usage

Basic Implementation

Create an instrumentation.js file in your project root:

export async function register() {
  // Initialize observability tools
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const monitoring = await import('@your-monitoring-tool')
    monitoring.init({
      serviceName: 'your-app-name',
      environment: process.env.NODE_ENV
    })
  }
}

Advanced Error Handling

Next.js 15 introduces a new onRequestError hook, developed in collaboration with Sentry, that provides comprehensive error tracking capabilities:

export async function onRequestError(error, request, context) {
  // Capture detailed error information
  const errorContext = {
    router: context.router, // 'pages' or 'app'
    serverComponent: context.serverComponent,
    serverAction: context.serverAction,
    routeHandler: context.routeHandler,
    middleware: context.middleware,
    url: request.url,
    method: request.method,
    error: {
      message: error.message,
      stack: error.stack,
      name: error.name
    }
  }

  // Send to your observability service
  await fetch('https://your-monitoring-service.com/api/errors', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${process.env.API_KEY}`
    },
    body: JSON.stringify(errorContext)
  })
}

export async function register() {
  // Initialize your observability SDK
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { initializeMonitoring } = await import('./monitoring')
    await initializeMonitoring()
  }
}

Error Context Information

The onRequestError hook provides detailed context about errors, including:

  • Router Type: Identifies whether the error occurred in the Pages Router or App Router
  • Server Context: Pinpoints the exact server component where the error originated:
    • Server Components
    • Server Actions
    • Route Handlers
    • Middleware
  • Request Details: Captures relevant request information for debugging
  • Error Information: Full error stack traces and messages

Common Use Cases

  1. Performance Monitoring
export async function register() {
  const { metrics } = await import('@monitoring/metrics')
  
  metrics.trackServerStart()
  metrics.watchMemoryUsage()
  metrics.watchCPUUsage()
}
  1. Database Connection Monitoring
export async function register() {
  const { db, monitor } = await import('./database')
  
  db.on('connect', () => monitor.logConnection())
  db.on('error', (error) => {
    monitor.logError(error)
    // Implement retry logic or alerting
  })
}
  1. OpenTelemetry Integration
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { NodeSDK } = await import('@opentelemetry/sdk-node')
    const { trace } = await import('@opentelemetry/api')
    
    const sdk = new NodeSDK({
      serviceName: 'your-next-app',
      traceExporter: yourPreferredExporter()
    })
    
    sdk.start()
  }
}

This stable instrumentation API provides a powerful foundation for monitoring and debugging Next.js applications in production. By leveraging these features, developers can build more reliable and observable applications while maintaining high performance and user experience.

Security and Deployment

Enhanced Server Actions Security

Two major security improvements:

  1. Dead Code Elimination

    • Unused server actions are removed
    • Reduces bundle size
    • Improves security
  2. Secure Action IDs

    • Non-deterministic ID generation
    • IDs change between builds
    • Prevents endpoint guessing

Self-Hosting Improvements

Next.js 15 makes self-hosting easier:

  • Custom Cache-Control headers are respected
  • Automatic sharp installation with next start
  • Better CDN compatibility
  • Default expiry time of one year

Migration Considerations

When upgrading to Next.js 15:

  1. Update async request APIs
  2. Review caching strategy
  3. Test server actions
  4. Check custom cache headers

Conclusion

Next.js 15 brings significant improvements to performance, security, and developer experience. While the async API changes require some migration effort, the benefits in performance and security make the upgrade worthwhile.

For more detailed information, visit the official Next.js documentation.

If you found this content helpful ⇢

Stay Tuned

Subscribe for development and indie hacking tips!