迁移指南
Nitro v3 引入了有意的不向后兼容更改。本指南将帮助你从 Nitro v2 迁移。
Note
这是一份关于从 Nitro 2 迁移到 3 的动态文档。在使用测试版期间,请定期查看。
大多数迁移遵循相同的顺序:
#nitropack 已重命名为 nitro
NPM 包 nitropack(v2)已重命名为 nitro(v3)。
迁移: 在 package.json 中将 nitropack 依赖更新为 nitro:
{
"dependencies": {
-- "nitropack": "latest"
++ "nitro": "latest"
}
}有关 nightly 构建的更多信息,请参阅 nightly channel 指南。
迁移: 搜索你的代码库,并将所有 nitropack 实例重命名为 nitro:
-- import { defineNitroConfig } from "nitropack/config"
++ import { defineConfig } from "nitro"#最低支持的 Node.js 版本:20
Nitro 现在要求最低 Node.js 版本为 20,因为 Node.js 18 已于 2025 年 4 月结束生命周期。
请升级到最新的 LTS 版本(>= 20)。
迁移:
- 使用
node --version检查本地 Node.js 版本,并在必要时进行更新。 - 如果你使用 CI/CD 系统进行部署,请确保你的流水线运行的是 Node.js 20 或更高版本。
- 如果你的托管服务商管理 Node.js 运行时,请确保其设置为版本 20、22 或更高版本。
#构建器按需安装
Nitro 默认使用 rolldown(或 rollup、vite)打包服务器,但它们都不是 Nitro 的依赖。构建器会从你的项目中解析,并在构建时按需安装。将其添加到项目依赖中即可固定版本:
npm i -D rolldown未安装 rolldown 时,nitro dev 会在没有构建器的情况下运行服务器源代码(builder: false)。
#自动导入已移除
Nitro v2 会自动让 defineEventHandler、useStorage、useRuntimeConfig、defineCachedFunction 和 defineNitroPlugin 等工具在服务器代码中无需导入即可使用(由 unimport 提供支持),同时还会公开 server/utils/ 的导出内容和虚拟的 #imports 模块。
Nitro v3 中已移除自动导入。imports 配置选项、#imports 模块和生成的 nitro-imports.d.ts 声明均不再可用。使用这些全局变量将导致构建或运行时错误。
迁移: 在所有位置添加显式导入。常用工具及其来源:
import { defineHandler, definePlugin, defineErrorHandler, HTTPError } from "nitro";
import { useKV } from "nitro/kv";
import { useRuntimeConfig } from "nitro/runtime-config";
import { defineCachedFunction, defineCachedHandler } from "nitro/cache";
import { useDatabase } from "nitro/database";
import { defineTask, runTask } from "nitro/task";
import { useNitroApp, useNitroHooks } from "nitro/app";
import { getQuery, getCookie } from "nitro/h3";你自己的 utils/ 目录中的工具也需要显式的(相对)导入:
import { defineHandler } from "nitro";
import { makeGreeting } from "../utils/hello.ts";
export default defineHandler(() => makeGreeting("Nitro"));#类型导入
Nitro 类型现在仅从 nitro/types 导出。
迁移: 从 nitro/types 导入类型,而不是从 nitro 导入:
-- import { NitroRuntimeConfig } from "nitropack"
++ import { NitroRuntimeConfig } from "nitro/types"#更改后的 Nitro 子路径导入
Nitro v2 引入了多个子路径导出,其中一些已被移除或更新:
nitropack/rollup、nitropack/core(使用nitro/builder)nitropack/runtime/*(使用nitro/*)nitropack/kit(已移除)nitropack/presets(已移除)nitropack/meta(改用nitro/meta,它只导出version、runtimeDir和runtimeDependencies)
此前引入了实验性的 nitropack/kit,但现在已将其移除。未来可能会推出独立的 Nitro Kit 包,并明确其目标。
迁移:
- 使用来自
nitro/types的NitroModule,而不是 kit 中的defineNitroModule。 - 优先使用内置的 Nitro 预设(外部预设仅用于评估)。
#服务器目录扫描需选择性启用
在 Nitro v2 中,srcDir 默认为项目根目录,并且始终会扫描 routes/、api/、middleware/、plugins/ 和 tasks/ 等目录。
在 Nitro v3 中:
srcDir选项已弃用,推荐使用serverDir(继续使用srcDir仍然有效,但会记录警告)。serverDir默认为false,这意味着在显式启用之前不会进行目录扫描。否则,扫描到的路由、中间件、插件和任务不会被注册。
迁移: 在 Nitro 配置中设置 serverDir:
import { defineConfig } from "nitro";
export default defineConfig({
serverDir: "./server", // or "." to keep the v2 root layout
});将 serverDir 设置为 true 等同于设置为 "server"。路径将相对于项目根目录解析。
#扫描文件中的保留后缀
Nitro v3 将扫描文件名末尾的小写后缀保留给自身约定使用。在 v2 中,routes/hello.world.ts 会注册为 /hello.world;在 v3 中,构建会因未知后缀而失败(开发模式下会跳过该文件并记录错误)。routes/sitemap.xml.ts 等已知文件扩展名仍然有效。
middleware/、plugins/、tasks/ 和 modules/ 文件名中的 .dev、.prod 和 .prerender 也属于保留后缀,使用这些后缀同样会导致构建失败。
测试文件(*.test.ts、*.spec.ts)和类型声明文件(*.d.ts)不再注册。
迁移: 重命名该文件,或将后缀添加到 scanSuffixes,以便将其保留为文件名的一部分。
#unenv 选项已弃用
unenv 配置选项(以及钩子中的 nitro.options.unenv)已弃用,请改用 alias、inject、polyfills 和 builtinModules 选项(unenv 的 polyfill 和 external 分别对应 polyfills 和 builtinModules)。传给 unenv 的预设仍然有效,但会记录一条警告。
export default defineConfig({
- unenv: {
- alias: { "my-module": "my-module/web" },
- external: ["cloudflare:workers"],
- },
+ alias: { "my-module": "my-module/web" },
+ builtinModules: ["cloudflare:workers"],
});通过钩子推送预设的模块应直接更新这些选项(例如 nitro.options.builtinModules.push(...))。在这些选项中设置的值会覆盖部署预设添加的默认值(例如 Cloudflare 和 Deno 会将受支持的 Node.js 内置模块映射到原生模块)。
unenv 不再是 Nitro 的依赖。当 node: false 构建导入目标运行时不支持的 Node.js 内置模块时,Nitro 会从你的项目中解析 unenv 并自动安装(不会提示确认)。如果你直接导入 unenv,请将其添加到项目依赖中。
#unstorage、db0 和 ocache 按需安装
unstorage、db0 和 ocache 不再是 Nitro 的依赖。使用时,Nitro 会从你的项目中解析并按需安装它们:
unstorage:导入nitro/kv(或nitro/storage)、配置kv挂载,或将cache.driver设为"kv"时。db0:启用experimental.database或导入nitro/database时。ocache:导入nitro/cache(defineCachedHandler、defineCachedFunction)或使用cache/swr路由规则时。
这些依赖会在不提示确认的情况下安装到项目依赖中。如果你直接导入 unstorage、db0 或 ocache,请自行将它们添加为项目依赖。
#已移除 App Config 支持
Nitro v2 支持捆绑的 app config,可以在 app.config.ts 中定义配置,并通过 useAppConfig() 在运行时访问这些配置。
此功能已被移除。
迁移:
在服务器目录中使用常规的 .ts 文件,并直接导入它。
#路由规则
路由规则的匹配和处理已移至 h3-rules。redirect、proxy、cors、headers、cache 和 swr 的规则形状现在由 h3-rules 定义,而 isr、prerender 和 static 仍是 Nitro 特有的规则。
NitroRouteConfig 和 NitroRouteRules 类型已弃用,推荐使用从 nitro/types 重新导出的 RouteRuleConfig 和 NormalizedRouteRules:
- import { NitroRouteConfig, NitroRouteRules } from "nitropack/types"
+ import { RouteRuleConfig, NormalizedRouteRules } from "nitro/types"getRouteRules(event) 已由 event.context.routeRules 替代。若要解析其他路径的规则,请使用 nitro/app 中的 getRouteRules(method, pathname).routeRules。
- import { getRouteRules } from "nitropack/runtime"
- const rules = getRouteRules(event)
+ import { getRouteRules } from "nitro/app"
+ const rules = event.context.routeRules
+ const { routeRules: blogRules } = getRouteRules("GET", "/blog/post")#运行时工具
运行时工具已移至单独的 nitro/* 子路径导出。有关用法,请参阅文档。
-- import { useStorage } from "nitropack/runtime/storage"
++ import { useKV } from "nitro/kv"| 工具 | Nitro v3 导入 |
|---|---|
useKV(原为 useStorage) | nitro/kv |
defineCachedFunction、defineCachedHandler | nitro/cache |
useDatabase | nitro/database |
useRuntimeConfig | nitro/runtime-config |
defineTask、runTask | nitro/task |
useNitroApp、useNitroHooks、getRouteRules | nitro/app |
Note
useStorage 已重命名为 useKV,nitro/storage 已重命名为 nitro/kv。storage 配置选项已重命名为 kv,而 devStorage 已由 $development 中的 kv 替代(如果你在预渲染期间依赖 devStorage,也请将其添加到 $prerender 中)。旧名称仍可作为已弃用的别名使用,并将在未来版本中移除。
#缓存存储
缓存函数和处理器默认不再使用存储层。条目存储在内存 LRU 存储中,可通过新的 cache 选项配置(driver: "memory" | "fs" | "kv")。
如果配置了 cache 存储挂载点(例如 storage: { cache: { driver: "redis" } }),缓存条目会继续存储在其中。如果缓存函数、处理器或路由规则使用自定义 base 指向另一个挂载点,或在运行时挂载缓存存储(例如在插件中调用 useKV().mount(...)),请设置 cache: { driver: "kv" }。
#内部服务器请求
要向你自己的服务器发起内部请求(v2 的 useNitroApp().localFetch 模式),请使用从 nitro 导出的 serverFetch 工具。此外,还有一个 fetch 导出,它会将绝对路径(以 / 开头)路由到服务器,并将其他所有内容路由到全局 fetch。
import { serverFetch } from "nitro";
const res = await serverFetch("/api/hello"); // returns a web Response#插件
defineNitroPlugin 工具已重命名为 definePlugin,现在从 nitro 中导入。
-- export default defineNitroPlugin((nitroApp) => {
++ import { definePlugin } from "nitro"
++
++ export default definePlugin((nitroApp) => {#可选钩子
如果你之前在 Nitro 插件之外使用 useNitroApp().hooks,它可能是未定义的。使用新的 useNitroHooks() 可以确保获得一个实例。
import { useNitroHooks } from "nitro/app";
useNitroHooks().hook("request", (event) => {
/* ... */
});#构建钩子重命名
rollup:before 和 rollup:reload 构建钩子会在所有构建器(Rollup、Rolldown 和 Vite)中运行,因此现已分别重命名为 build:config 和 build:reload。build:config 钩子接收 { builder, rollup } 或 { builder, rolldown },而不是单独的打包器配置。使用 Vite 构建器时,builder 为 "vite",配置对应于 Vite 所用的打包器。
-- nitro.hooks.hook("rollup:before", (nitro, config) => {
-- config.plugins.push(myPlugin());
++ nitro.hooks.hook("build:config", (nitro, { builder, rollup, rolldown }) => {
++ const config = rollup ?? rolldown;
++ config.plugins.push(builder === "rollup" ? myRollupPlugin() : myPlugin());
});旧名称仍可作为已弃用的别名使用(会记录警告):rollup:before 钩子由 build:config 以单独的配置参数调用,rollup:reload 钩子则由 build:reload 调用。使用 nitro.hooks.callHook() 调用旧名称不再会运行任何钩子。
#错误处理器
defineNitroErrorHandler 工具已重命名为 defineErrorHandler,现在从 nitro 导入。
-- export default defineNitroErrorHandler((error, event) => {
++ import { defineErrorHandler } from "nitro"
++
++ export default defineErrorHandler((error, event) => {#H3 v2
Nitro v3 升级到 H3 v2,其中包含 API 更改。所有 H3 工具从 nitro/h3 导入。
#Web 标准
H3 v2 基于 Web 标准原语(URL、Headers、Request 和 Response)重写。
仅在 Node.js 运行时中可访问 event.node.{req,res}。event.web 已重命名为 event.req(Web Request 的实例)。
#响应处理
你应该始终显式地 return 响应体或 throw 一个错误:
-- import { send, sendRedirect, sendStream } from "nitro/h3"
-- send(event, value)
-- sendStream(event, stream)
-- sendRedirect(event, location, code)
++ import { redirect } from "nitro/h3"
++ return value
++ return stream
++ return redirect(location, code)其他更改:
sendError(event, error)→throw error(或throw new HTTPError(...))sendNoContent(event)→return noContent()sendProxy(event, target)→return proxy(event, target)
#请求体
大多数 body 工具可以被原生的 event.req 方法替代:
-- import { readBody, readRawBody, readFormData } from "nitro/h3"
++ // 使用原生 Request 方法
++ const json = await event.req.json()
++ const text = await event.req.text()
++ const formData = await event.req.formData()
++ const stream = event.req.body#请求头
H3 现在使用标准 Web Headers。请求头的值始终是纯 string(没有 null、undefined 或 string[])。
-- import { getHeader, setHeader, getResponseStatus } from "nitro/h3"
-- getHeader(event, "x-foo")
-- setHeader(event, "x-foo", "bar")
++ event.req.headers.get("x-foo")
++ event.res.headers.set("x-foo", "bar")
++ event.res.status // 替代 getResponseStatus(event)#处理器工具
-- import { eventHandler, defineEventHandler } from "nitro/h3"
++ import { defineHandler } from "nitro"lazyEventHandler→defineLazyEventHandleruseBase→withBase
#错误工具
-- import { createError, isError } from "nitro/h3"
++ import { HTTPError } from "nitro"
++ throw new HTTPError({ status: 404, message: "未找到" })
++ HTTPError.isError(error)#Node.js 工具
-- import { defineNodeListener, fromNodeMiddleware, toNodeListener } from "nitro/h3"
++ import { defineNodeHandler, fromNodeHandler, toNodeHandler } from "nitro/h3"#预设更新
Nitro 预设已针对最新兼容性进行更新。
一些(旧版)预设已被移除或重命名。
| 旧预设 | 新预设 |
|---|---|
node(Node.js 中间件) | node_middleware(导出已更改为 middleware) |
cloudflare、cloudflare_worker、cloudflare_module_legacy | cloudflare_module |
deno-server-legacy | 使用 Deno v2 的 deno_server |
netlify-builder | netlify 或 netlify_edge |
vercel-edge | 启用 Fluid compute 的 vercel |
azure、azure_functions | azure_swa |
firebase | firebase_app_hosting |
iis | iis_handler |
deno(Deno Deploy)、deno_deploy | deno_server |
edgio | 已停止维护 |
cli | 因缺乏使用而移除 |
service_worker | 因不稳定而移除 |
Warning
node 和 deno 预设名称在 v3 中仍然存在,但它们现在指向不同的目标:
- 在 v2 中,
node预设会生成可复用的 Node.js 中间件。在 v3 中,node是node_server的别名,会构建一个完整的独立 Node.js 服务器。如果保留preset: "node",现在将获得一个独立服务器。使用node_middleware以保留 v2 的中间件输出。 - 在 v2 中,
deno和deno_deploy预设面向 Deno Deploy Classic(打包为server/index.ts并通过deployctl部署)。Deno Deploy Classic 已于 2026 年 7 月 20 日关闭。在 v3 中,deno和deno_deploy是deno_server的别名,会构建.output/server/index.mjs。新版 Deno Deploy 使用此输出(参阅 Deno Deploy 指南)。
#AWS Amplify 默认运行时
由于 Node.js 20 已于 2026 年 4 月结束生命周期,aws_amplify 预设现在默认使用 nodejs22.x 计算运行时(此前为 nodejs20.x)。
迁移:
- 在 Node.js 22 上测试应用,或在 Nitro 配置中通过
awsAmplify: { runtime: "nodejs24.x" }显式固定运行时。
#Cloudflare Dev 和 Vercel 可观测性不再受兼容日期限制
此前受 compatibilityDate 控制的两项预设功能现在始终启用,因此从 v2 沿用较早兼容日期的配置也会保留这些功能:
cloudflare_module、cloudflare_durable和cloudflare_pages预设在开发环境中始终使用cloudflare-dev预设(通过 Miniflare 模拟并提供绑定)。此前,compatibilityDate早于2025-07-13时会静默回退到通用的nitro-dev预设。vercel预设始终会生成可观测性路由。此前,这些路由要求compatibilityDate为2025-07-15或更晚。
#Azure Functions v4 编程模型
azure_swa 预设现在使用 Azure Functions 的 Node.js v4 编程模型部署服务器,不再使用 function.json。项目依赖中需要 @azure/functions v4:
npm i @azure/functions@^4迁移:
- 将
@azure/functions@^4添加到依赖中(缺少时 Nitro 会提示安装)。如果已安装 v3,请更新它。 - 若要继续使用旧版 v3 编程模型,请在 Nitro 配置中设置
azure: { functionsVersion: 3 }。
#Vercel ISR 路由规则
在 Nitro v2 中,vercel 预设会将 swr、static 和 cache: false 路由规则转换为 Vercel ISR 配置。在 Nitro v3 中,只有 isr 路由规则会为 Vercel 配置 ISR;swr / cache 规则则像其他平台一样使用 Nitro 内置缓存层。用于启用此行为的 future.nativeSWR 选项已移除。
迁移:
原先依赖 Vercel ISR 的地方请改用 isr 路由规则,并从配置中移除 future.nativeSWR。
export default defineConfig({
-- future: { nativeSWR: true },
routeRules: {
-- "/blog/**": { swr: true },
-- "/api/realtime/**": { cache: false },
++ "/blog/**": { isr: true },
++ "/api/realtime/**": { isr: false },
},
});#Netlify 输出目录
netlify 和 netlify_edge 预设现在会将输出写入 Netlify Frameworks API 指定的目录:
| 输出 | 之前 | 之后 |
|---|---|---|
服务器函数(netlify) | .netlify/functions-internal | .netlify/v1/functions |
边缘函数(netlify_edge) | .netlify/edge-functions | .netlify/v1/edge-functions |
部署配置(netlify.config) | .netlify/deploy/v1/config.json | .netlify/v1/config.json |
边缘函数配置现在会内联到 server.mjs,而不再写入 .netlify/edge-functions/manifest.json;netlify_edge 预设也会应用 netlify.config。
迁移:
- 更新引用旧目录的 CI 脚本或缓存路径。
- 使用
netlify deploy --no-build部署本地构建时,请先清理.netlify/functions-internal和.netlify/edge-functions中旧构建遗留的文件。
#Cloudflare Pages 重定向目标
Cloudflare Pages 预设不再为生成的 _redirects 文件中的相对 redirect 目标添加 baseURL 前缀。现在目标会按原样使用,与服务器运行时以及 Vercel、Netlify 预设的行为一致。路由规则键(匹配路径)仍相对于 baseURL。EdgeOne 预设在此前的 v3 预发布版本中也会添加前缀,现在同样采用这一行为。
迁移:
如果使用非根路径的 baseURL,请在相对重定向目标中包含该前缀:
export default defineConfig({
baseURL: "/app/",
routeRules: {
-- "/old/**": { redirect: "/new/**" },
++ "/old/**": { redirect: "/app/new/**" },
},
});#Cloudflare 绑定访问
在 Nitro v2 中,可以通过 event.context.cloudflare.env 访问 Cloudflare 环境变量和绑定。
在 Nitro v3 中,Cloudflare 运行时上下文改为附加到请求的运行时对象上。
迁移:
-- const { cloudflare } = event.context
-- const binding = cloudflare.env.MY_BINDING
++ const { env } = event.req.runtime.cloudflare
++ const binding = env.MY_BINDING#Cloudflare Email 和 Queue 钩子
cloudflare:email 和 cloudflare:queue 运行时钩子中已移除已弃用的 event 字段,请改用 message 和 batch。
迁移:
-- nitroApp.hooks.hook("cloudflare:email", ({ event }) => {})
++ nitroApp.hooks.hook("cloudflare:email", ({ message }) => {})
-- nitroApp.hooks.hook("cloudflare:queue", ({ event }) => {})
++ nitroApp.hooks.hook("cloudflare:queue", ({ batch }) => {})#Cloudflare 导出
较早的 v3 预发布版本曾实验性支持从 exports.cloudflare.ts 文件(或 cloudflare.exports 选项)导出 Durable Objects、Workflows 和其他 Cloudflare 类。现在应改为从 server.ts 文件导出,并且在本地开发中也可使用。参阅 Durable Objects。
++ export { MyWorkflow } from "./exports.cloudflare.ts";
++
++ export default {
++ fetch() {},
++ };#Vite 插件选项
较早的 v3 预发布版本中,services、assetsImport 和 serverReload 只能作为 experimental.vite 选项传给 nitro() Vite 插件。它们现已移至顶层 vite 选项,也可以放在 Vite 配置的 nitro 项下或写入 nitro.config.ts。experimental.vite 仍可使用,但已弃用。已弃用的 ServiceConfig 类型已移除,请改用 ViteServiceConfig。
-- nitro({ experimental: { vite: { services: { api: { entry: "./api.ts" } } } } })
++ nitro({ vite: { services: { api: { entry: "./api.ts" } } } })#已移除的弃用选项
此前 v3 预发布版本中已弃用或不起作用的部分选项和导出已移除:
netlify.images:改用netlify.config.images。vercel.regions:它仅适用于已移除的vercel-edge预设。请改用vercel.functions.regions。prerender.retry和prerender.retryDelay:它们在 v3 中不起作用。- 从
nitro/storage导入的useKV:请改为从nitro/kv导入。 nitro/builder中的getBuildInfo(rootDir):请传入选项对象getBuildInfo({ rootDir })。