# Next.js 16.4 and React 19.3 across my side projects

All my side projects are Next.js on the front, most with a Go service behind, and they all run on the box at home. When a minor release lands I upgrade one, leave it a day, and then do the rest in a batch. [Next.js 16.4](https://nextjs.org/blog) came out on 6 October, so this weekend was batch weekend.

The headline in 16.4 is that Cache Components are now the recommended way to build every app, and `create-next-app` switches them on by default. When Next 16 came out last year, `cacheComponents: true` was an opt-in. Existing apps don't get flipped for you, which I think is right, because it does change behaviour. With it on, everything is dynamic unless you mark it with `"use cache"`, and the static parts of a page are prerendered as a shell while the dynamic parts stream in under `<Suspense>`. I'd moved most of my apps to it over the past year anyway, so this release mostly confirmed where things were heading.

There's also `ensureStatic`, which lets you say a route must stay static so the build fails if something dynamic sneaks in. I like the idea a lot for pages that are built from a data file, but check the release notes for exactly how to apply it, as I'm still getting used to it. Then there are new navigation and prefetch APIs, which I've read about and haven't used, so I won't try to explain them. And `next upgrade --agent`, which hands the upgrade to a coding agent along with the migration notes. I tried it on my smallest app, where there was almost nothing to change, so it bumped the packages, ran the build and stopped. Not much of a test. I'd want to see it on a messier upgrade, and I'd still read the diff. The rest of the release is performance: a smaller disk cache, lazy server HMR, a shared Turbopack runtime and smaller production bundles. I did notice the disk cache, since the box at home is never far from full.

## React 19.3

[React 19.3](https://react.dev/blog) came out on 9 September, bundled into 16.4. Two experimental features went stable, `<ViewTransition>` and Fragment refs, and there are no breaking changes, which is why it's 19.3 and not 20.

`<ViewTransition>` wraps the browser's View Transitions API in a component. React decides when a transition starts (a navigation, a `startTransition`, a Suspense reveal) and you say what should animate. On AI Radar I'd wanted the small cover image in the feed to grow into the big one on the issue page, so that's where I tried it:

```tsx
// feed
import { ViewTransition } from "react";

<Link href={`/issue/${issue.id}`}>
  <ViewTransition name={`cover-${issue.id}`}>
    <img src={issue.cover} alt="" width={120} height={80} />
  </ViewTransition>
  <h2>{issue.title}</h2>
</Link>

// issue page
<ViewTransition name={`cover-${issue.id}`}>
  <img src={issue.cover} alt="" width={960} height={640} />
</ViewTransition>
```

The same `name` on both sides and the browser morphs one into the other. Browsers without View Transitions just navigate normally. Names have to be unique on the page when the transition runs, and it's worth switching the animation off for people who've asked for reduced motion:

```css
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}
```

Fragment refs let you put a `ref` on a `<Fragment>` and reach its DOM children without a wrapper `div`. I've only had one place where a wrapper would have broken a CSS grid, and I'd read the [docs](https://react.dev/reference/react/Fragment) for the exact API rather than trust my memory of it.

The upgrade itself was the usual:

```bash
npm install next@16.4 react@19.3 react-dom@19.3 eslint-config-next@16.4
npm run build
```

Most apps built and passed their smoke tests first time. A couple needed small fixes, mainly a component reading `cookies()` without a Suspense boundary above it, which older versions had let me get away with, and an old experimental ViewTransition import. My deploys build on the Mac and ship only the standalone output, so a bad upgrade would have been one image to roll back. I didn't need to.

---

*First published on [my blog](https://blogs.kishankanejiiya.tech/posts/next-16-4-and-react-19-3). Cover photo: Alexander Novikov, CC BY-SA 4.0, via Wikimedia Commons ([source](https://commons.wikimedia.org/wiki/File:Hot-air_balloon_in_Tambov_-_02.jpg)).*

