H3 version 2 includes some behavior and API changes that you need to consider applying when migrating.
If your application is currently using CommonJS modules (require and module.exports), You can still use require("h3") thanks to require(esm) supported in latest Node.js versions.
You can alternatively use other compatible runtimes Bun or Deno.
When using Node.js, H3 uses a compatibility layer (💥 srvx) and in other runtimes uses native web compatibility APIs.
Access to the native event.node.{req,res} is only available when running server in Node.js runtime.
event.web is renamed to event.req (instance of web Request).
If you were previously using methods below, you can replace them with return statements returning a text, JSON, stream, or web Response (h3 smartly detects and handles each):
send(event, value): Migrate to return <value>.sendError(event, <error>): Migrate to throw createError(<error>).sendStream(event, <stream>): Migrate to return <stream>.sendWebResponse(event, <response>): Migrate to return <response>.Other send utils that are renamed and need explicit return:
sendNoContent(event) / return null: Migrate to return noContent(event).sendIterable(event, <value>): Migrate to return iterable(event, <value>).sendProxy(event, target): Migrate to return proxy(event, target).handleCors(event): Check return value and early return if handled(not false).serveStatic(event, content): Make sure to add return before.sendRedirect(event, location, code): Migrate to return redirect(event, location, code).createApp() and createRouter() you can use new H3().Any handler can return a response. If middleware don't return a response, next handlers will be tried and finally make a 404 if neither responses. Router handlers can return or not return any response, in this case, H3 will send a simple 200 with empty content.
H3 migrated to a brand new route-matching engine (🌳 rou3). You might experience slight (but more intuitive) behavior changes for matching patterns.
Other changes from v1:
app.use("/path", handler) only matches /path (not /path/foo/bar). For matching all subpaths like before, it should be updated to app.use("/path/**", handler).event.path received in each handler will have a full path without omitting the prefixes. use withBase(base, handler) utility to make prefixed app. (example: withBase("/api", app.handler)).router.add(path, method: Method | Method[] signature is changed to router.add(method: Method, path)router.use(path, handler) is deprecated. Use router.all(path, handler) instead.app.use(() => handler, { lazy: true }) is no supported anymore. Instead you can use app.use(defineLazyEventHandler(() => handler), { lazy: true }).app.use(["/path1", "/path2"], ...) and app.use("/path", [handler1, handler2]) are not supported anymore. Instead, use multiple app.use() calls.app.resolve(path) removed.event.req.* methods which is based on web Request interface.readBody(event) utility will use JSON.parse or URLSearchParams for parsing requests with application/x-www-form-urlencoded content-type.
Behavior changes:
GET method for example) but instead, return empty values.request.json and readBody does not use unjs/destr anymore. You should always filter and sanitize data coming from user to avoid prototype-poisoning.Headers for all utils.Header values are always a plain string now (no null or undefined or number or string[]).
For the Set-Cookie header, you can use headers.getSetCookie that always returns a string array.
H3 v2 deprecated some legacy and aliased utilities.
createApp / createRouter: Migrate to new H3().createError/H3Error: Migrate to HTTPErrorisError: Migrate to HTTPError.isErroreventHandler/defineEventHandler: Migrate to defineHandler (you can also directly use a function!).lazyEventHandler: Migrate to defineLazyEventHandler.isEventHandler: (removed) Any function can be an event handler.useBase: Migrate to withBase.defineRequestMiddleware and defineResponseMiddleware removed.getHeader / getRequestHeader: Migrate to event.req.headers.get(name).getHeaders / getRequestHeaders: Migrate to Object.fromEntries(event.req.headers.entries()).getRequestPath: Migrate to event.path or event.url.getMethod: Migrate to event.method.getResponseHeader / getResponseHeaders: Migrate to event.res.headers.get(name)setHeader / setResponseHeader / setHeaders / setResponseHeaders: Migrate to event.res.headers.set(name, value).appendHeader / appendResponseHeader / appendResponseHeaders: Migrate to event.res.headers.append(name, value).removeResponseHeader / clearResponseHeaders: Migrate to event.res.headers.delete(name)appendHeaders: Migrate to appendResponseHeaders.defaultContentType: Migrate to event.res.headers.set("content-type", type)getResponseStatus / getResponseStatusText / setResponseStatus: Use event.res.status and event.res.statusText.defineNodeListener: Migrate to defineNodeHandler.fromNodeMiddleware: Migrate to fromNodeHandler.toNodeListener: Migrate to toNodeHandler.createEvent: (removed): Use Node.js adapter (toNodeHandler(app)).fromNodeRequest: (removed): Use Node.js adapter (toNodeHandler(app)).promisifyNodeListener (removed).callNodeListener: (removed).fromPlainHandler: (removed) Migrate to Web API.toPlainHandler: (removed) Migrate to Web API.fromPlainRequest (removed) Migrate to Web API or use mockEvent util for testing.callWithPlainRequest (removed) Migrate to Web API.fromWebRequest: (removed) Migrate to Web API.callWithWebRequest: (removed).readRawBody: Migrate to event.req.text() or event.req.arrayBuffer().getBodyStream / getRequestWebStream: Migrate to event.req.body.readFormData / readMultipartFormData / readFormDataBody: Migrate to event.req.formData().isStream: Migrate to instanceof ReadableStream.isWebResponse: Migrate to instanceof Response.splitCookiesString: Use splitSetCookieString from cookie-es.MIMES: (removed).App: Migrate to H3.AppOptions: Migrate to H3Config._RequestMiddleware: Migrate to RequestMiddleware._ResponseMiddleware: Migrate to ResponseMiddleware.NodeListener: Migrate to NodeHandler.TypedHeaders: Migrate to RequestHeaders and ResponseHeaders.HTTPHeaderName: Migrate to RequestHeaderName and ResponseHeaderName.H3Headers: Migrate to native Headers.H3Response: Migrate to native Response.MultiPartData: Migrate to native FormData.RouteNode: Migrate to RouterEntry.
CreateRouterOptions: Migrate to RouterOptions.Removed type exports: WebEventContext, NodeEventContext, NodePromisifiedHandler, AppUse, Stack, InputLayer, InputStack, Layer, Matcher, PlainHandler, PlainRequest, PlainResponse, WebHandler.