next-upgrade

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Next.js Upgrade Workflow

Next.js 升级工作流

Structured 9-step workflow for upgrading Next.js applications across major versions. Handles codemod automation, dependency updates, breaking change resolution, and validation.
用于跨主版本升级Next.js应用的9步结构化工作流,支持codemod自动化、依赖更新、破坏性变更解决以及验证功能。

When to Apply

适用场景

Use this skill when:
  • Upgrading Next.js to a new major version (13, 14, 15, 16)
  • Running codemods to automate breaking change migrations
  • Resolving deprecation warnings in an existing Next.js project
  • Planning an incremental migration path for large codebases
  • Validating that an upgrade did not introduce regressions
当你有以下需求时可使用本工作流:
  • 将Next.js升级到新的主版本(13、14、15、16)
  • 运行codemod自动完成破坏性变更迁移
  • 解决现有Next.js项目中的弃用警告
  • 为大型代码库规划增量迁移路径
  • 验证升级没有引入回归问题

9-Step Upgrade Workflow

9步升级工作流

Step 1: Detect Current Version

步骤1:检测当前版本

Identify the current Next.js version and target version.
bash
undefined
确认当前的Next.js版本和目标升级版本。
bash
undefined

Check current version

Check current version

cat package.json | grep '"next"'
cat package.json | grep '"next"'

Check Node.js version (Next.js 15+ requires Node 18.18+, Next.js 16 requires Node 20+)

Check Node.js version (Next.js 15+ requires Node 18.18+, Next.js 16 requires Node 20+)

node --version

**Version Requirements:**

| Next.js | Minimum Node.js | Minimum React |
| ------- | --------------- | ------------- |
| 13      | 16.14           | 18.2.0        |
| 14      | 18.17           | 18.2.0        |
| 15      | 18.18           | 19.0.0        |
| 16      | 20.0            | 19.0.0        |
node --version

**版本要求:**

| Next.js | 最低Node.js版本 | 最低React版本 |
| ------- | --------------- | ------------- |
| 13      | 16.14           | 18.2.0        |
| 14      | 18.17           | 18.2.0        |
| 15      | 18.18           | 19.0.0        |
| 16      | 20.0            | 19.0.0        |

Step 2: Create Upgrade Branch

步骤2:创建升级分支

bash
git checkout -b upgrade/nextjs-{target-version}
Always upgrade on a dedicated branch. Never upgrade on main directly.
bash
git checkout -b upgrade/nextjs-{target-version}
请始终在专属分支上执行升级操作,永远不要直接在main分支上升级。

Step 3: Run Codemods

步骤3:运行Codemods

Use the official Next.js codemod CLI to automate breaking change migrations.
bash
undefined
使用官方Next.js codemod CLI自动完成破坏性变更迁移。
bash
undefined

Interactive mode (recommended) -- selects applicable codemods

Interactive mode (recommended) -- selects applicable codemods

npx @next/codemod@latest upgrade latest
npx @next/codemod@latest upgrade latest

Or target a specific version

Or target a specific version

npx @next/codemod@latest upgrade 15 npx @next/codemod@latest upgrade 16

**Key Codemods by Version:**
npx @next/codemod@latest upgrade 15 npx @next/codemod@latest upgrade 16

**各版本核心Codemod:**

Next.js 13 to 14

Next.js 13 到 14

  • next-image-to-legacy-image
    -- Renames
    next/image
    imports to
    next/legacy/image
  • next-image-experimental
    -- Migrates from
    next/legacy/image
    to new
    next/image
  • metadata
    -- Moves Head metadata to Metadata API exports
  • next-image-to-legacy-image
    -- 将
    next/image
    导入重命名为
    next/legacy/image
  • next-image-experimental
    -- 从
    next/legacy/image
    迁移到新的
    next/image
  • metadata
    -- 将Head元数据迁移到Metadata API导出

Next.js 14 to 15

Next.js 14 到 15

  • next-async-request-apis
    -- Converts synchronous dynamic APIs (
    cookies()
    ,
    headers()
    ,
    params
    ,
    searchParams
    ) to async
  • next-dynamic-ssr-false
    -- Replaces
    ssr: false
    with
    { loading }
    pattern for
    next/dynamic
  • next-og-import
    -- Moves OG image generation imports to
    next/og
  • next-async-request-apis
    -- 将同步动态API(
    cookies()
    headers()
    params
    searchParams
    )转换为异步形式
  • next-dynamic-ssr-false
    -- 将
    next/dynamic
    ssr: false
    替换为
    { loading }
    模式
  • next-og-import
    -- 将OG图片生成的导入路径迁移到
    next/og

Next.js 15 to 16

Next.js 15 到 16

  • next-use-cache
    -- Converts
    unstable_cache
    to
    'use cache'
    directive
  • next-cache-life
    -- Migrates cache revalidation to
    cacheLife()
    API
  • next-form
    -- Wraps
    <form>
    elements with
    next/form
    where applicable
  • next-use-cache
    -- 将
    unstable_cache
    转换为
    'use cache'
    指令
  • next-cache-life
    -- 将缓存重验证逻辑迁移到
    cacheLife()
    API
  • next-form
    -- 在适用的场景下用
    next/form
    包裹
    <form>
    元素

Step 4: Update Dependencies

步骤4:更新依赖

bash
undefined
bash
undefined

Update Next.js and React together

Update Next.js and React together

npm install next@latest react@latest react-dom@latest
npm install next@latest react@latest react-dom@latest

For Next.js 15+, also update React types

For Next.js 15+, also update React types

npm install -D @types/react@latest @types/react-dom@latest
npm install -D @types/react@latest @types/react-dom@latest

Update eslint config

Update eslint config

npm install -D eslint-config-next@latest

**Peer Dependency Conflicts:**

If you encounter peer dependency conflicts:

1. Check which packages require older React/Next versions
2. Update those packages first, or check for newer versions
3. Use `--legacy-peer-deps` only as a last resort (document why)
npm install -D eslint-config-next@latest

**Peer依赖冲突处理:**

如果遇到peer依赖冲突:

1. 检查哪些包依赖旧版本的React/Next
2. 先更新这些包,或者查找是否有可用的新版本
3. 仅作为最后手段使用`--legacy-peer-deps`(请记录使用原因)

Step 5: Update Configuration

步骤5:更新配置

Review and update
next.config.js
/
next.config.ts
:
javascript
// next.config.ts (Next.js 15+ recommends TypeScript config)
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  // Next.js 15+: experimental features that graduated
  // Remove these from experimental:
  // - serverActions (now stable in 14+)
  // - appDir (now stable in 14+)
  // - ppr (now stable in 16+)

  // Next.js 16+: new cache configuration
  cacheComponents: true,  // Enable component-level caching
};

export default nextConfig;
Configuration Changes by Version:
VersionChange
14
appDir
removed from experimental (now default)
14
serverActions
removed from experimental (now stable)
15
bundlePagesRouterDependencies
now default true
15
swcMinify
removed (now always enabled)
16
dynamicIO
replaces several caching behaviors
16
cacheComponents: true
enables component caching
检查并更新
next.config.js
/
next.config.ts
javascript
// next.config.ts (Next.js 15+ recommends TypeScript config)
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  // Next.js 15+: experimental features that graduated
  // Remove these from experimental:
  // - serverActions (now stable in 14+)
  // - appDir (now stable in 14+)
  // - ppr (now stable in 16+)

  // Next.js 16+: new cache configuration
  cacheComponents: true,  // Enable component-level caching
};

export default nextConfig;
各版本配置变更:
版本变更说明
14
appDir
已从experimental中移除(现在是默认特性)
14
serverActions
已从experimental中移除(现在已稳定)
15
bundlePagesRouterDependencies
现在默认值为true
15已移除
swcMinify
配置(现在默认始终开启)
16
dynamicIO
替代了多项缓存行为
16配置
cacheComponents: true
可启用组件缓存

Step 6: Resolve Breaking Changes

步骤6:解决破坏性变更

After running codemods, manually resolve remaining breaking changes.
Common Breaking Changes (15 to 16):
  1. Async Request APIs:
    cookies()
    ,
    headers()
    ,
    params
    ,
    searchParams
    are now async
    typescript
    // Before (Next.js 14)
    export default function Page({ params }: { params: { id: string } }) {
      const { id } = params;
    }
    
    // After (Next.js 15+)
    export default async function Page({ params }: { params: Promise<{ id: string }> }) {
      const { id } = await params;
    }
  2. Caching Default Changed:
    fetch()
    requests are no longer cached by default in Next.js 15+
    typescript
    // Before: cached by default
    fetch('https://api.example.com/data');
    
    // After: explicitly opt-in to caching
    fetch('https://api.example.com/data', { cache: 'force-cache' });
    // Or use 'use cache' directive in Next.js 16
  3. Route Handlers: GET route handlers are no longer cached by default
    typescript
    // Next.js 15+: explicitly set caching
    export const dynamic = 'force-static';
运行codemod后,手动解决剩余的破坏性变更。
常见破坏性变更(15到16):
  1. 异步请求API
    cookies()
    headers()
    params
    searchParams
    现在都是异步的
    typescript
    // Before (Next.js 14)
    export default function Page({ params }: { params: { id: string } }) {
      const { id } = params;
    }
    
    // After (Next.js 15+)
    export default async function Page({ params }: { params: Promise<{ id: string }> }) {
      const { id } = await params;
    }
  2. 缓存默认值变更:Next.js 15+中
    fetch()
    请求默认不再缓存
    typescript
    // Before: cached by default
    fetch('https://api.example.com/data');
    
    // After: explicitly opt-in to caching
    fetch('https://api.example.com/data', { cache: 'force-cache' });
    // Or use 'use cache' directive in Next.js 16
  3. 路由处理器:GET路由处理器默认不再缓存
    typescript
    // Next.js 15+: explicitly set caching
    export const dynamic = 'force-static';

Step 7: Run Tests

步骤7:运行测试

bash
undefined
bash
undefined

Run existing test suite

Run existing test suite

npm test
npm test

Run build to catch compile-time errors

Run build to catch compile-time errors

npm run build
npm run build

Run dev server and check key pages manually

Run dev server and check key pages manually

npm run dev

**Validation Checklist:**

- [ ] Build completes without errors
- [ ] All existing tests pass
- [ ] Key user flows work in dev mode
- [ ] No console warnings about deprecated APIs
- [ ] Server-side rendering works correctly
- [ ] Client-side navigation works correctly
- [ ] API routes return expected responses
- [ ] Middleware functions correctly
- [ ] Static generation (SSG) pages build correctly
npm run dev

**验证检查清单:**

- [ ] 构建无错误完成
- [ ] 所有现有测试通过
- [ ] 核心用户流程在开发模式下正常运行
- [ ] 控制台没有弃用API相关的警告
- [ ] 服务端渲染正常工作
- [ ] 客户端导航正常工作
- [ ] API路由返回预期响应
- [ ] 中间件功能正常
- [ ] 静态生成(SSG)页面构建正常

Step 8: Update TypeScript Types

步骤8:更新TypeScript类型

bash
undefined
bash
undefined

Regenerate TypeScript declarations

Regenerate TypeScript declarations

npm run build
npm run build

Fix any new type errors

Fix any new type errors

npx tsc --noEmit

**Common Type Fixes:**

- `PageProps` type changes (params/searchParams become Promise in 15+)
- `Metadata` type updates (new fields added)
- `NextRequest`/`NextResponse` API changes
- Route handler parameter types
npx tsc --noEmit

**常见类型修复:**

- `PageProps`类型变更(15+版本中params/searchParams变为Promise类型)
- `Metadata`类型更新(新增了字段)
- `NextRequest`/`NextResponse` API变更
- 路由处理器参数类型变更

Step 9: Document and Commit

步骤9:记录并提交

bash
undefined
bash
undefined

Create detailed commit

Create detailed commit

git add -A git commit -m "chore: upgrade Next.js from {old} to {new}
Breaking changes resolved:
  • [list specific changes]
Codemods applied:
  • [list codemods run]
Manual fixes:
  • [list manual changes]"
undefined
git add -A git commit -m "chore: upgrade Next.js from {old} to {new}
Breaking changes resolved:
  • [list specific changes]
Codemods applied:
  • [list codemods run]
Manual fixes:
  • [list manual changes]"
undefined

Incremental Upgrade Path

增量迁移路径

For large version jumps (e.g., 13 to 16), upgrade incrementally:
Next.js 13 -> 14 -> 15 -> 16
Why incremental?
  • Codemods are version-specific and may not compose correctly across multiple versions
  • Easier to debug issues when changes are smaller
  • Each version has its own set of breaking changes to resolve
  • Tests can validate each intermediate step
For each version step:
  1. Run codemods for that version
  2. Update deps
  3. Fix breaking changes
  4. Run tests
  5. Commit checkpoint
  6. Proceed to next version
对于跨多个大版本升级的场景(例如13到16),请采用增量升级方式:
Next.js 13 -> 14 -> 15 -> 16
为什么要增量升级?
  • Codemod是版本专属的,跨多个版本运行可能无法正常工作
  • 变更范围更小,更容易调试问题
  • 每个版本都有自己的一套破坏性变更需要解决
  • 可以在每个中间步骤运行测试验证
每个版本升级步骤:
  1. 运行对应版本的codemod
  2. 更新依赖
  3. 修复破坏性变更
  4. 运行测试
  5. 提交检查点
  6. 继续升级下一个版本

Troubleshooting

故障排查

Build fails after upgrade

升级后构建失败

  1. Clear
    .next
    directory:
    rm -rf .next
  2. Clear node_modules:
    rm -rf node_modules && npm install
  3. Clear Next.js cache:
    rm -rf .next/cache
  1. 清除
    .next
    目录:
    rm -rf .next
  2. 清除node_modules:
    rm -rf node_modules && npm install
  3. 清除Next.js缓存:
    rm -rf .next/cache

Module not found errors

模块未找到错误

  1. Check if package was renamed or merged
  2. Update imports per migration guide
  3. Check if package needs separate update
  1. 检查对应包是否被重命名或合并
  2. 按照迁移指南更新导入路径
  3. 检查是否需要单独更新该包

Hydration mismatches after upgrade

升级后hydration不匹配

  1. Check for server/client rendering differences
  2. Ensure dynamic imports use correct options
  3. Verify date/locale handling is consistent
  1. 检查服务端/客户端渲染差异
  2. 确保动态导入使用了正确的配置项
  3. 验证日期/区域处理逻辑是一致的

Middleware issues

中间件问题

  1. Middleware API changed in Next.js 13 (moved to root)
  2. NextResponse.rewrite()
    behavior changed in 15
  3. Check matcher configuration syntax
  1. Next.js 13中中间件API变更(移动到根目录)
  2. Next.js 15中
    NextResponse.rewrite()
    行为变更
  3. 检查matcher配置语法

Iron Laws

铁律

  1. ALWAYS upgrade on a dedicated branch, never on main directly — upgrade branches can be rebased or reverted without disrupting production; direct main upgrades risk deploying half-migrated code.
  2. NEVER skip intermediate versions in a multi-version jump — Next.js codemods are version-specific and do not compose correctly across major versions; skipping steps leaves un-migrated breaking changes.
  3. ALWAYS run official codemods before making manual changes — codemods handle the bulk of mechanical migrations; manual-first approaches miss patterns and create divergence from the reference migration path.
  4. NEVER use
    --legacy-peer-deps
    without documenting the specific conflict and resolution plan — suppressing peer errors hides version conflicts that will cause runtime failures.
  5. ALWAYS validate with a full build plus test suite before merging — the dev server does not exercise SSG, edge runtime, or build optimizations that can fail silently post-upgrade.
  1. 永远在专属分支上升级,不要直接在main分支上操作——升级分支可以随时变基或回滚,不会影响生产环境;直接在main分支升级可能会部署未完成迁移的代码。
  2. 永远不要在多版本升级时跳过中间版本——Next.js的codemod是版本专属的,跨主版本无法正常工作;跳过步骤会遗留未迁移的破坏性变更。
  3. 永远在手动修改前先运行官方codemod——codemod可以处理大部分机械化的迁移工作;先手动修改会遗漏通用模式,导致和参考迁移路径不一致。
  4. 永远不要在没有记录具体冲突和解决方案的情况下使用
    --legacy-peer-deps
    ——抑制peer依赖错误会隐藏版本冲突,最终导致运行时错误。
  5. 永远在合并前通过完整构建和测试套件验证——开发服务器不会运行SSG、边缘运行时、构建优化这些升级后可能静默失败的逻辑。

Anti-Patterns

反模式

Anti-PatternWhy It FailsCorrect Approach
Upgrading on the main branch directlyHalf-migrated code can reach production; rollback requires a revert commitAlways create
upgrade/nextjs-{version}
branch; merge only after full validation
Skipping intermediate versionsVersion-specific codemods are not composable; skipped breaking changes cause runtime failuresUpgrade one major version at a time: 13→14→15→16; commit a checkpoint at each step
Manual migration before running codemodsCreates divergence from codemod output; codemods cannot merge cleanly with manual editsRun codemods first; apply manual fixes only for patterns codemods could not handle
Using
--legacy-peer-deps
without documentation
Hidden version conflicts cause runtime failures not visible at install timeResolve conflicts explicitly; use the flag only with a documented justification
Validating only in dev modeDev server skips SSG, edge runtime, and build optimizations that can fail post-upgradeRun
npm run build
plus the full test suite; check SSR, SSG, and API routes explicitly
反模式失败原因正确做法
直接在main分支上升级未完成迁移的代码可能进入生产环境;回滚需要提交revert始终创建
upgrade/nextjs-{version}
分支;仅在完成完整验证后才合并
跳过中间版本升级版本专属的codemod无法组合使用;跳过的破坏性变更会导致运行时失败每次仅升级一个主版本:13→14→15→16;每个步骤都提交检查点
运行codemod前先手动迁移会导致和codemod输出不一致;codemod无法和手动修改干净合并先运行codemod;仅对codemod无法处理的模式进行手动修复
未记录原因就使用
--legacy-peer-deps
隐藏的版本冲突会导致安装时不可见的运行时错误显式解决冲突;仅在有书面说明理由的情况下使用该flag
仅在开发模式下验证开发服务器会跳过SSG、边缘运行时、构建优化这些升级后可能失败的逻辑运行
npm run build
和完整测试套件;显式检查SSR、SSG和API路由

References

参考资料