Le Do Nghiem

Le Do Nghiem

AI Engineer

About meBooksSnippetsBlog

© 2026 Le Do Nghiem. All rights reserved.

Contact |

Back to Blog

What's New in Next.js 15?

Le Do Nghiem
Le Do NghiemAI Engineer
2025-09-01 4 min read
Share

What actually changed for me

Next.js 15 shipped a lot of headlines: Partial Prerendering, caching changes, async request APIs. I cared less about the keynote slides and more about one question: what breaks in my existing App Router projects, and what gets easier?

This post is my honest field notes — not a full changelog. If you are still fuzzy on Server vs Client Components, read use client vs use server first. That mental model makes 15's changes click.


Caching stopped being "automatic magic"

What changed: Fetch caching defaults and cache semantics shifted. Things I assumed were cached sometimes were not — and vice versa.

Why it matters: "It worked in dev" stopped being a reliable signal. I had to read cache behavior per route again instead of trusting muscle memory from Next 13.

What I do now:

  • Be explicit with cache: 'force-cache', no-store, or revalidate when I care about freshness
  • Use unstable_cache (or the stable equivalent in your version) for expensive reads I want to dedupe
// app/blog/[slug]/page.tsx
import { unstable_cache } from "next/cache";

async function getPost(slug) {
  const res = await fetch(`https://api.example.com/posts/${slug}`);
  return res.json();
}

export default async function BlogPost({ params }) {
  const post = await unstable_cache(getPost, ["post", params.slug])(params.slug);

  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

Red flag: Sprinkling no-store everywhere because caching is confusing. You will pay in latency and cost. Decide per page what "fresh enough" means.


Partial Prerendering in plain language

What: Ship a static shell fast, stream the dynamic parts.

Why I like it: Marketing pages with one personalized widget. Docs with a logged-in banner. The static part hits CDN; the dynamic part does not block first paint as hard.

What I do not use it for (yet): Fully dynamic dashboards where every pixel depends on live data. PPR helps hybrid pages most.

Red flag: Treating PPR as "free performance" without measuring. Profile LCP before and after.


Async request APIs

Route params and search params became async in the App Router world. That sounds small. It broke a surprising amount of copy-pasted code.

What I learned: params and searchParams are Promises in server components now. await them before use.

Why: Clearer streaming and layout composition on the server. The migration pain is front-loaded.


What broke for me

  1. Assuming old fetch defaults — pages refetched more (or less) than expected after upgrade.
  2. Client boundaries too high — still the main bundle-size issue; 15 did not fix that by itself. See use client vs use server.
  3. Third-party libs not ready — some auth and analytics packages lagged behind async APIs. I pinned versions and read migration guides instead of fighting npm.

What actually got better

  • Clearer forcing function on server-first design — if you were already splitting Server and Client Components well, 15 rewards that structure.
  • Caching as an explicit choice — more verbose, but easier to reason about once you name the policy per route.
  • Ecosystem catching up — React 19 features (Actions, etc.) pair nicely with App Router patterns. I wrote more on that in Exploring React 19.

My upgrade checklist

Upgrade when you have time to read the migration guide — not Friday afternoon before a release.

My upgrade checklist:

  1. Grep for params. and searchParams. in server components — add await where needed.
  2. List every fetch and document its cache intent.
  3. Re-run Lighthouse on your three slowest pages.
  4. Re-read use client vs use server and shrink any bloated 'use client' trees.

Next.js 15 is not a new framework. It is a stricter teacher about caching and server boundaries. That is annoying for a week and useful for the next year.

On this page

  • What actually changed for me
  • Caching stopped being "automatic magic"
  • Partial Prerendering in plain language
  • Async request APIs
  • What broke for me
  • What actually got better
  • My upgrade checklist
Share
Next Post

Building AI-Powered Apps with Next.js and LangChain