The Evolution of Next.js 15

Next.js 15 represents the stabilization of modern React architecture. Where earlier App Router versions suffered from confusing implicit caching behaviors, Next.js 15 defaults to explicit, developer-controlled configurations.

For engineering teams shipping production web apps, this means fewer stale cache bugs, predictable fetch lifecycles, and substantially faster Turbopack builds.

Uncached by Default: The Mental Shift

In Next.js 14, `fetch` requests were cached by default unless specified otherwise. This led to surprising bugs where dynamic user data was unintentionally cached across sessions. Next.js 15 flips this behavior:

// Next.js 15: Requests are dynamic by default
const res = await fetch('https://api.domain.com/v1/orders'); // NOT cached by default

// To explicitly opt into static caching:
const staticData = await fetch('https://api.domain.com/v1/tiers', {
  cache: 'force-cache',
  next: { tags: ['pricing-tiers'] },
});

This single change aligns Next.js with standard HTTP mental models, reducing developer cognitive load.

Streaming SSR with React Suspense

To eliminate blank screens while waiting for heavy database queries, Next.js 15 leverages React Suspense streaming. Instead of waiting for the slowest query before returning any HTML, the shell is delivered instantly:

export default function DashboardPage() {
  return (
    <div className="space-y-6">
      <DashboardHeader />
      <Suspense fallback={<MetricsSkeleton />}>
        <RealtimeMetricsFeed />
      </Suspense>
    </div>
  );
}

Turbopack Performance in CI/CD

With Turbopack now stable for development and local bundling, local HMR updates occur in under 50 milliseconds even on repos containing over 1,500 modules.