Migration guide for v1 to v2
H3 version 2 includes some behavior and API changes that you need to consider applying when migrating.
Latest Node.js and ESM-only
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.
Web Standards
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 Response).
Response Handling
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 toreturn <value>
.sendError(event, <error>)
: Migrate tothrow createError(<error>)
.sendStream(event, <stream>)
: Migrate toreturn <stream>
.sendWebResponse(event, <response>)
: Migrate toreturn <response>
.
Other send utils that are renamed and need explicit return
:
sendNoContent(event)
/return null
: Migrate toreturn noContent(event)
.sendIterable(event, <value>)
: Migrate toreturn iterable(event, <value>)
.sendProxy(event, target)
: Migrate toreturn proxy(event, target)
.handleCors(event)
: Check return value (boolean) and earlyreturn
if handled.serveStatic(event, content)
: Make sure to addreturn
before.sendRedirect(event, location, code)
: Migrate toreturn redirect(event, location, code)
.
H3 and Router
Instead of
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:
- Middleware added with
app.use("/path", handler)
only matches/path
(not/path/foo/bar
). For matching all subpaths like before, it should be updated toapp.use("/path/**", handler)
. - The
event.path
received in each handler will have a full path without omitting the prefixes. usewithBase(base, handler)
utility to make prefixed app. (example:withBase("/api", app.handler)
). router.add(path, method: Method | Method[]
signature is changed torouter.add(method: Method, path)
router.use(path, handler)
is deprecated. Userouter.all(path, handler)
instead.app.use(() => handler, { lazy: true })
is no supported anymore. Instead you can useapp.use(defineLazyEventHandler(() => handler), { lazy: true })
.app.use(["/path1", "/path2"], ...)
andapp.use("/path", [handler1, handler2])
are not supported anymore. Instead, use multipleapp.use()
calls.app.resolve(path)
removed.
Request Body
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.
- For text: Use event.req.text().
- For json: Use event.req.json().
- For formData: Use event.req.formData().
- For stream: Use event.req.body.
Behavior changes:
- Body utils won't throw an error if the incoming request has no body (or is a
GET
method for example) but instead, return empty values. - Native
request.json
andreadBody
does not use unjs/destr anymore. You should always filter and sanitize data coming from user to avoid prototype-poisoning.
Cookie and Headers
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.
Other Deprecations
H3 v2 deprecated some legacy and aliased utilities.
App and router utils
createApp
/createRouter
: Migrate tonew H3()
.
Error utils
createError
/H3Error
: Migrate toHTTPError
isError
: Migrate toHTTPError.isError
Handler utils
eventHandler
/defineEventHandler
: Migrate todefineHandler
(you can also directly use a function!).lazyEventHandler
: Migrate todefineLazyEventHandler
.toEventHandler
: Remove wrapper.isEventHandler
: (removed) Any function can be an event handler.useBase
: Migrate towithBase
.defineRequestMiddleware
anddefineResponseMiddleware
removed.
Request utils
getHeader
/getRequestHeader
: Migrate toevent.req.headers.get(name)
.getHeaders
/getRequestHeaders
: Migrate toObject.fromEntries(event.req.headers.entries())
.getRequestPath
: Migrate toevent.path
orevent.url
.getMethod
: Migrate toevent.method
.
Response utils
getResponseHeader
/getResponseHeaders
: Migrate toevent.res.headers.get(name)
setHeader
/setResponseHeader
/setHeaders
/setResponseHeaders
: Migrate toevent.res.headers.set(name, value)
.appendHeader
/appendResponseHeader
/appendResponseHeaders
: Migrate toevent.res.headers.append(name, value)
.removeResponseHeader
/clearResponseHeaders
: Migrate toevent.res.headers.delete(name)
appendHeaders
: Migrate toappendResponseHeaders
.defaultContentType
: Migrate toevent.res.headers.set("content-type", type)
getResponseStatus
/getResponseStatusText
/setResponseStatus
: Useevent.res.status
andevent.res.statusText
.
Node.js utils
defineNodeListener
: Migrate todefineNodeHandler
.fromNodeMiddleware
: Migrate tofromNodeHandler
.toNodeListener
: Migrate totoNodeHandler
.createEvent
: (removed): Use Node.js adapter (toNodeHandler(app)
).fromNodeRequest
: (removed): Use Node.js adapter (toNodeHandler(app)
).promisifyNodeListener
(removed).callNodeListener
: (removed).
Web Utils
fromPlainHandler
: (removed) Migrate to Web API.toPlainHandler
: (removed) Migrate to Web API.fromPlainRequest
(removed) Migrate to Web API or usemockEvent
util for testing.callWithPlainRequest
(removed) Migrate to Web API.fromWebRequest
: (removed) Migrate to Web API.callWithWebRequest
: (removed).
Body Utils
readRawBody
: Migrate toevent.req.text()
orevent.req.arrayBuffer()
.getBodyStream
/getRequestWebStream
: Migrate toevent.req.body
.readFormData
/readMultipartFormData
/readFormDataBody
: Migrate toevent.req.formData()
.
Other Utils
isStream
: Migrate toinstanceof ReadableStream
.isWebResponse
: Migrate toinstanceof Response
.splitCookiesString
: UsesplitSetCookieString
from cookie-es.MIMES
: (removed).
Type Exports
App
: Migrate toH3
.AppOptions
: Migrate toH3Config
._RequestMiddleware
: Migrate toRequestMiddleware
._ResponseMiddleware
: Migrate toResponseMiddleware
.NodeListener
: Migrate toNodeHandler
.TypedHeaders
: Migrate toRequestHeaders
andResponseHeaders
.HTTPHeaderName
: Migrate toRequestHeaderName
andResponseHeaderName
.H3Headers
: Migrate to nativeHeaders
.H3Response
: Migrate to nativeResponse
.MultiPartData
: Migrate to nativeFormData
.RouteNode
: Migrate toRouterEntry
.CreateRouterOptions
: Migrate toRouterOptions
.
Removed type exports: WebEventContext
, NodeEventContext
, NodePromisifiedHandler
, AppUse
, Stack
, InputLayer
, InputStack
, Layer
, Matcher
, PlainHandler
, PlainRequest
, PlainResponse
, WebHandler
.