Skip to content

Commit 176aac8

Browse files
authored
cover more breaking changes in upgrade flow (#13)
1 parent ea7b2b0 commit 176aac8

File tree

2 files changed

+161
-10
lines changed

2 files changed

+161
-10
lines changed

src/mcp-prompts/nextjs-16-critical-rules.md

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,33 @@ export async function GET(request: Request, props) {
4444
}
4545
```
4646

47+
**Metadata Image Routes (opengraph-image, twitter-image, icon, apple-icon):**
48+
```typescript
49+
// ❌ BEFORE (Next.js 15)
50+
export default function Image({ params, id }) {
51+
const slug = params.slug
52+
const imageId = id // string
53+
// ...
54+
}
55+
56+
export async function generateImageMetadata({ params }) {
57+
return [{ id: '1' }, { id: '2' }]
58+
}
59+
60+
// ✅ AFTER (Next.js 16)
61+
export default async function Image(props, id) {
62+
const params = await props.params // params now async
63+
const imageId = await id // id is now Promise<string> when using generateImageMetadata
64+
const slug = params.slug
65+
// ...
66+
}
67+
68+
export async function generateImageMetadata(props) {
69+
const params = await props.params
70+
return [{ id: '1' }, { id: '2' }]
71+
}
72+
```
73+
4774
### 2. Async Dynamic Functions
4875
**cookies(), headers(), draftMode()**
4976

@@ -96,7 +123,51 @@ revalidateTag('posts', 'max') // For background invalidation
96123

97124
## ⚙️ Config Migrations
98125

99-
### Image Defaults Changed (No Action Needed)
126+
### 1. Turbopack Config Rename (REQUIRED for canary users)
127+
```typescript
128+
// ❌ BEFORE
129+
// next.config.js
130+
export default {
131+
turbopackPersistentCachingForDev: true,
132+
}
133+
134+
// ✅ AFTER
135+
// next.config.js
136+
export default {
137+
turbopackFileSystemCacheForDev: true,
138+
}
139+
```
140+
141+
### 2. ESLint Config Removal (REQUIRED)
142+
```typescript
143+
// ❌ BEFORE - Remove this from next.config.js
144+
export default {
145+
eslint: {
146+
ignoreDuringBuilds: true,
147+
dirs: ['app', 'src'],
148+
},
149+
}
150+
151+
// ✅ AFTER - Move to .eslintrc.json or eslint.config.js
152+
// ESLint configuration should now be in dedicated ESLint config files
153+
```
154+
155+
### 3. serverComponentsExternalPackages (BREAKING)
156+
```typescript
157+
// ❌ BEFORE - In experimental
158+
export default {
159+
experimental: {
160+
serverComponentsExternalPackages: ['package-name'],
161+
},
162+
}
163+
164+
// ✅ AFTER - Top-level config
165+
export default {
166+
serverComponentsExternalPackages: ['package-name'],
167+
}
168+
```
169+
170+
### 4. Image Defaults Changed (No Action Needed)
100171
These changed automatically - override if needed:
101172
- `minimumCacheTTL`: 60s → 14400s (4 hours)
102173
- `qualities`: [1..100][75]
@@ -136,7 +207,7 @@ import { ViewTransition } from 'react'
136207

137208
## 📁 Parallel Routes Requirement
138209

139-
If you have `@modal`, `@auth`, etc. folders:
210+
If you have `@modal`, `@auth`, etc. folders (any `@` folder except `@children`):
140211

141212
```typescript
142213
// MUST create: app/@modal/default.tsx
@@ -145,6 +216,8 @@ export default function Default() {
145216
}
146217
```
147218

219+
**Note:** `@children` is a special implicit slot and does NOT require a `default.js` file.
220+
148221
## 🛡️ Image Security
149222

150223
If using local images with query strings:
@@ -206,12 +279,17 @@ export default async function Page(props) {
206279
- [ ] `function Layout({ params })``async function Layout(props)` + `await props.params`
207280
- [ ] `generateMetadata({ params })``async generateMetadata(props)` + `await props.params`
208281
- [ ] `generateViewport({ params })``async generateViewport(props)` + `await props.params`
282+
- [ ] Metadata image routes: `function Image({ params, id })``async function Image(props, id)` + `await props.params` + `await id`
283+
- [ ] `generateImageMetadata({ params })``async generateImageMetadata(props)` + `await props.params`
209284
- [ ] `cookies().get()``(await cookies()).get()`
210285
- [ ] `headers().get()``(await headers()).get()`
211286
- [ ] `draftMode().isEnabled``(await draftMode()).isEnabled`
212287
- [ ] `revalidateTag(tag)``updateTag(tag, 'max')` or `revalidateTag(tag, 'max')`
213288

214-
**Config changes:**
289+
**Config changes in next.config.js:**
290+
- [ ] Rename `turbopackPersistentCachingForDev``turbopackFileSystemCacheForDev`
291+
- [ ] Remove `eslint` config object (move to .eslintrc.json or eslint.config.js)
292+
- [ ] Move `serverComponentsExternalPackages` out of `experimental` to top-level
215293
- [ ] Add `default.tsx` for all parallel route `@` folders
216294
- [ ] Update `unstable_ViewTransition``ViewTransition`
217295
- [ ] Review image config defaults (if using local images with query strings)

src/mcp-prompts/upgrade-nextjs-16-prompt.md

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,15 @@ After the codemod runs, check for any remaining issues it might have missed:
103103
### Manual Check Checklist:
104104

105105
**A. Parallel Routes (NOT handled by codemod)**
106-
Files: Check for @ folders
106+
Files: Check for @ folders (except `@children`)
107107
Requirement: All parallel route slots must have `default.js` files
108108
Impact: Build fails without them
109109

110+
**Note:** `@children` is a special implicit slot and does NOT require a `default.js` file.
111+
110112
Fix if missing:
111113
```typescript
112-
// Create: app/@modal/default.js
114+
// Create: app/@modal/default.js (for @modal, @auth, etc.)
113115
export default function Default() {
114116
return null
115117
}
@@ -145,19 +147,68 @@ After the codemod runs, check for any remaining issues it might have missed:
145147
1. Use Biome: `biome check .`
146148
2. Use ESLint directly: `<pkg-exec> @next/codemod@canary next-lint-to-eslint-cli .`
147149

148-
**E. --turbopack Flags (No Longer Needed)**
150+
**E. next.config.js Turbopack Config Updates (REQUIRED for canary users)**
151+
File: next.config.js
152+
Check: `turbopackPersistentCachingForDev` config option
153+
Action: Rename to `turbopackFileSystemCacheForDev`
154+
155+
```diff
156+
// next.config.js
157+
export default {
158+
- turbopackPersistentCachingForDev: true,
159+
+ turbopackFileSystemCacheForDev: true,
160+
}
161+
```
162+
163+
Note: This was a temporary change on canary - not everyone has this config
164+
165+
**F. --turbopack Flags (No Longer Needed)**
149166
Files: package.json scripts
150167
Check: `next dev --turbopack`, `next build --turbopack`
151168
Action: Remove `--turbopack` flags (Turbopack is default in v16)
152169
Note: Use `--webpack` flag if you want webpack instead
153170

154-
**F. Edge Cases the Codemod May Miss**
171+
**G. ESLint Config Removal (REQUIRED)**
172+
File: next.config.js
173+
Check: `eslint` configuration object
174+
Action: Remove eslint config from next.config.js
175+
176+
```diff
177+
// next.config.js
178+
export default {
179+
- eslint: {
180+
- ignoreDuringBuilds: true,
181+
- dirs: ['app', 'src'],
182+
- },
183+
}
184+
```
185+
186+
Note: ESLint configuration should now be in .eslintrc.json or eslint.config.js
187+
Migration: Use `<pkg-exec> @next/codemod@canary next-lint-to-eslint-cli .` if needed
188+
189+
**H. serverComponentsExternalPackages Deprecation (BREAKING)**
190+
File: next.config.js
191+
Check: `serverComponentsExternalPackages` in experimental config
192+
Action: Move out of experimental - this is now a top-level config option
193+
194+
```diff
195+
// next.config.js
196+
export default {
197+
- experimental: {
198+
- serverComponentsExternalPackages: ['package-name'],
199+
- },
200+
+ serverComponentsExternalPackages: ['package-name'],
201+
}
202+
```
203+
204+
**I. Edge Cases the Codemod May Miss**
155205
Review these manually:
156206

157207
- Complex async destructuring patterns
158208
- Dynamic params in nested layouts
159209
- Route handlers with cookies()/headers() in conditionals
160210
- Custom metadata generation with complex logic
211+
- Metadata image routes (opengraph-image, twitter-image, icon, apple-icon)
161212

162213
**CRITICAL: Only change if function actually uses these 5 APIs:**
163214
1. `params` from props
@@ -171,7 +222,26 @@ After the codemod runs, check for any remaining issues it might have missed:
171222
- `generateStaticParams()`
172223
- Any function that doesn't use the 5 APIs above
173224

174-
**G. ViewTransition API Renamed (NOT handled by codemod)**
225+
**METADATA IMAGE ROUTES - Important Changes:**
226+
For metadata image route files (opengraph-image, twitter-image, icon, apple-icon):
227+
- The first argument changes from `{ params }` to `params` (aligned with other App Router routes)
228+
- `params` is now async: `await props.params`
229+
- The second argument `id` becomes `Promise<string>` when using `generateImageMetadata`
230+
231+
```typescript
232+
// ❌ BEFORE
233+
export default function Image({ params, id }) {
234+
const slug = params.slug
235+
}
236+
237+
// ✅ AFTER
238+
export default async function Image(props, id) {
239+
const params = await props.params
240+
const imageId = await id // if using generateImageMetadata
241+
}
242+
```
243+
244+
**J. ViewTransition API Renamed (NOT handled by codemod)**
175245
Files: Search for imports of `unstable_ViewTransition` from React
176246
Action: Rename to `ViewTransition` (now stable in v16)
177247

@@ -180,7 +250,7 @@ After the codemod runs, check for any remaining issues it might have missed:
180250
+ import { ViewTransition } from 'react'
181251
```
182252

183-
**H. revalidateTag API Changes (Deprecation - NOT handled by codemod)**
253+
**K. revalidateTag API Changes (Deprecation - NOT handled by codemod)**
184254
Files: Search for `revalidateTag(` calls
185255
Check: All revalidateTag calls now require a profile parameter
186256

@@ -210,7 +280,7 @@ After the codemod runs, check for any remaining issues it might have missed:
210280

211281
Load `nextjs16://knowledge/cache-invalidation` for detailed API semantics and migration patterns.
212282

213-
**I. Deprecated Features (WARNINGS - Optional)**
283+
**L. Deprecated Features (WARNINGS - Optional)**
214284
- `middleware.ts` → consider renaming to `proxy.ts`
215285
- `next/legacy/image` → use `next/image`
216286
- `images.domains` → use `images.remotePatterns`
@@ -304,6 +374,9 @@ Issues the codemod couldn't handle:
304374
[ ] Parallel routes missing default.js
305375
[ ] Image security config needed
306376
[ ] Lint commands to update
377+
[ ] next.config.js: turbopackPersistentCachingForDev → turbopackFileSystemCacheForDev
378+
[ ] next.config.js: Remove eslint config object
379+
[ ] next.config.js: Move serverComponentsExternalPackages out of experimental
307380
[ ] revalidateTag API changes
308381
[ ] Edge cases in async APIs
309382
[ ] Deprecated features to update

0 commit comments

Comments
 (0)