用途
nextjs-ops 是一份围绕 Next.js App Router 的运营面(operational surface)技能文档,用来回答应用里“什么跨越了服务端/客户端边界、应用实际处在哪一套缓存模型、为什么响应是陈旧的、Server Action 在链路上究竟是什么”这类问题。它明确把自己定位为框架层面的技能:React 本身归 react-ops,样式归 tailwind-ops,上层的 CMS 归 payloadcms-ops,下层的 Workers 运行时归 cloudflare-ops / hono-ops。
文档声称已针对 Next.js 16.x 校验(记录日期 2026-08-30,next@16.3.3,文档快照 2026-08-25,React 19)。它指出语义在 15.0(fetch 默认不缓存、请求 API 异步)和 16.0(Cache Components、proxy.ts、revalidateTag 签名)发生过实质变化,因此在回答任何缓存问题前必须先确定应用版本——对 14 正确的答案对 16 是错的。
主要能力
版本与模型定向
提供三条命令,用于在任何建议之前先判定应用处于哪套模型:读取 next 版本号、检查 next.config 中的 cacheComponents、列出现有的 proxy / middleware 文件。据此区分三种情况:cacheComponents: true 时为 Cache Components 模型(不使用 'use cache' 就不缓存,PPR 为默认渲染);16.x 默认且无 cacheComponents 时为上一代模型(fetch 默认不缓存、路由段配置、unstable_cache);Next.js ≤ 14 为遗留模型(fetch 默认缓存,多数“为什么是旧数据”的 bug 出在这里)。
决策树
按任务类型分流到对应参考文档:陈旧数据排查、缓存取舍与失效、use client 报错与序列化失败、变更操作(Server Action 对 Route Handler)、数据获取与流式、路由与渲染、proxy.ts 与运行时、部署、版本升级、优化、测试,以及用脚本审计既有应用。
边界规则
文档强调边界是模块图而非文件夹:'use client' 标记的是客户端模块图的入口,该文件导入的一切(以及被导入文件再导入的一切)都会打进浏览器包,无论是否带指令;而通过 children 或 props 传入的组件不会被它导入,所以留在服务端并以已渲染输出到达。由此推出几条规则:Provider 应包裹 {children} 而不是整棵树;跨边界序列化失败才是真正的错误(类实例、函数、URL、Symbol、带 Date 的 ORM 行无法通过),修法通常是不要再发送不可序列化的东西,而是发送 UI 实际渲染的形状——这也是安全修法,因为把数据库原始行返回给客户端等于公开其全部列;环境变量泄漏是静默的,只有 NEXT_PUBLIC_* 会到达浏览器,其他变量在客户端模块中变成空字符串而不报错,可用 import 'server-only' 转为构建错误。
缓存模型
文档给出跨版本仍然成立的思维模型:工作要么在构建期已知、要么以声明寿命缓存、要么在请求时产生,每个缓存 bug 都属于三者被误分类。在 Cache Components 下,'use cache' 是唯一启用缓存的方式,必须显式声明 cacheLife 与 cacheTag;参数与闭包捕获变量构成缓存键;缓存作用域内不能读取 cookies()、headers()、searchParams 与动态参数;默认存储是实例内内存,在 serverless 上往往不跨请求存活,'use cache: remote' 是持久共享变体但需要网络往返。文档还列出 default、seconds、minutes、hours、days、weeks、max 等 profile 的 stale、revalidate、expire 数值,并说明 revalidate: 0 或 expire 低于 5 分钟会让内容掉出预渲染,stale 低于 30 秒会掉出预取。在上一代模型下,fetch 需要显式请求才缓存,非 fetch 工作通过 unstable_cache 缓存,路由段由 dynamic、revalidate、fetchCache 导出控制。
变更后的失效按“必须改变什么”选择:updateTag(tag) 在同一响应内过期并重读(read-your-own-writes,仅限 Action);revalidateTag(tag, profile) 为 stale-while-revalidate,不立即重渲染;revalidatePath(path) 使单个 URL 失效;refresh() 只重取未缓存数据、不动缓存(仅限 Action)。单参数 revalidateTag('x') 在 16 中已废弃。
Server Actions 安全
文档把 Server Action 定义成公开端点:'use server' 会把实现从客户端包中编译掉,只留一个 action ID 回传到路由;任何能发这个 POST 的人都能调用它。示例强调先鉴权、再按所有权重新从可信来源读取记录、只接受引用而非记录本身、Schema 校验只检查形状不检查权限,并指出“表单只对管理员渲染”或 proxy.ts matcher 都不构成授权。同时说明框架自带的保护(Origin 与 Host 的 CSRF 检查、1MB 请求体上限、加密的 action ID、未使用 action 的死代码消除、闭包变量加密)只是底线。GET、webhook、第三方调用、文件流、需要自定义状态/头或需要并行的场景应优先用 Route Handler,因为客户端派发 action 是逐个进行的。
踩坑清单
文档按“损失小时数”排序列出不易察觉的问题:next dev 从不缓存页面,必须用 next build && next start 验证;缓存作用域读取请求数据可能通过构建却在启动后失败;构建挂起约 50 秒后失败通常是 'use cache' 边界外创建的 Promise 在边界内被 await;在 layout 顶部 await params 会让整个子树退出静态;proxy.ts 没有 matcher 会对所有请求运行包括静态资源,而 _next/data 即使被排除仍会走 proxy;并行路由槽位自 16 起必须要有 default.js;爬虫按 user agent 获得完整动态渲染;缓冲代理会让流式静默失效;新部署出现 “Failed to find Server Action” 与多实例需共享 NEXT_SERVER_ACTIONS_ENCRYPTION_KEY;revalidateTag() 只失效所在实例;unstable_cache 与 'use cache' 不是同一存储,use cache 条目以构建 id 为键、跨部署不存活;缓存作用域内 Math.random()/Date.now() 会把一个值冻结给所有人。
使用方式
随附资源包括:scripts/audit-app-router.py(审计或接手应用,16 条静态规则,按检测到的 Next.js 主版本抑制不适用规则,八条规则描述的是 15 或 16 引入的破坏)、scripts/check-nextjs-facts.py(校验版本事实是否仍然成立,--offline 检查版本事实仍被正文提及且时效说明与目录一致,--live 确认各包的 npm 主版本)、assets/next.config.template.ts、assets/nextjs-facts.json。审计脚本从 node_modules/next 或 package.json 读取主版本,判定结果行会说明它依据的主版本;在无法读取版本的裸子目录可用 --assume-major N。文档给出示例:python scripts/audit-app-router.py /path/to/project、--min-severity error、--json、--assume-major 15 ./packages/web/app。
参考文档列表包括 caching-model、cache-components、server-client-boundary、server-actions、data-fetching-streaming、routing-and-rendering、proxy-and-runtimes、deployment、upgrading、optimization、testing。
适用场景
适合在 Next.js App Router 项目上做缓存排障、边界设计、Server Action 安全审查、部署与多实例配置、版本升级评估,以及接手陌生代码库时的静态审计。
限制
文档未提供收费、价格与授权信息。其版本事实具有时效性,正文本身也要求用 check-nextjs-facts.py 校验。审计脚本的规则有主版本门槛,跨版本使用需指定主版本。正文中关于 Cloudflare 路径的内容被截断,具体细节暂未提供。