npm / h3
h3
What changed in h3 1 to 2, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-20.
28 breaking6 security25 deprecations2 new APIs and options2 behavior and defaults1 fixes and other
See which of these apply to your code, ranked, in your agent:
npx @unstale/cli inith3 259 changes
Breaking changes 28
The App type export migrates to H3.
app.resolve(path) has been removed.
app.use("/path", handler) now matches only /path; use /path/** to match subpaths.
Array paths and arrays of handlers are no longer supported; use multiple app.use() calls.
The AppOptions type export migrates to H3Config.
createEvent was removed; use the Node.js adapter toNodeHandler(app).
CreateRouterOptions migrates to RouterOptions.
Lazy handlers must be wrapped with defineLazyEventHandler instead of passing a factory directly to app.use.
H3 v2 is ESM-only; latest Node.js versions can still load it with require("h3") through require(esm).
Handler event.path now includes the full path without omitting prefixes; withBase can create a prefixed app.
event.web is renamed to event.req, which is an instance of the web Request interface.
getRequestProtocol no longer trusts x-forwarded-proto by default; opt in with xForwardedProto behind a trusted proxy or CDN.
H3Headers migrates to the native Headers type.
H3Response migrates to the native Response type.
H3 uses standard web Headers for utilities, and header values are always strings.
isEventHandler was removed; any function can be an event handler.
Replace sendIterable(event, value) with return iterable(value).
MIMES has been removed.
Replace sendNoContent(event) or return null with return noContent().
H3 v2 requires Node.js >= 20.19.
The NodeListener type export migrates to NodeHandler.
Replace sendProxy(event, target) with return proxy(event, target).
Replace sendRedirect(event, location, code) with return redirect(location, code).
Body utilities return empty values instead of throwing when a request has no body, such as for GET requests.
Handlers should explicitly return response bodies or throw errors; H3 detects returned text, JSON, streams, and web Responses.
RouteNode migrates to RouterEntry.
A router handler that returns no response now produces a simple 200 with empty content.
The signature changes from router.add(path, method) to router.add(method, path).
Security 1
Native request.json and readBody no longer use destr; filter and sanitize user data to avoid prototype poisoning.
Deprecations 25
Response header append utilities are deprecated; use event.res.headers.append(name, value).
createApp and createRouter are deprecated; migrate to new H3().
createError and H3Error are deprecated; migrate to HTTPError.
createEventStream is deprecated; migrate to new EventStream(event).
eventHandler and defineEventHandler are deprecated; migrate to defineHandler or use a function directly.
defineNodeListener is deprecated; migrate to defineNodeHandler.
event.headers is deprecated; use event.req.headers.
event.method is deprecated; use event.req.method.
event.path is deprecated; use event.url.pathname + event.url.search.
fromNodeMiddleware is deprecated; migrate to fromNodeHandler.
getHeader and getRequestHeader are deprecated; use event.req.headers.get(name).
getHeaders and getRequestHeaders are deprecated; use Object.fromEntries(event.req.headers.entries()).
getMethod is deprecated; use event.req.method.
getRequestPath is deprecated; use event.url.pathname.
getResponseHeader and getResponseHeaders are deprecated; use event.res.headers.get(name).
Response status utilities are deprecated; use event.res.status and event.res.statusText.
isError is deprecated; migrate to HTTPError.isError.
lazyEventHandler is deprecated; migrate to defineLazyEventHandler.
Form-data body utilities are deprecated; use event.req.formData().
readRawBody is deprecated; use event.req.text() or event.req.arrayBuffer().
removeResponseHeader and clearResponseHeaders are deprecated; use event.res.headers.delete(name).
router.use(path, handler) is deprecated; use router.all(path, handler) instead.
Response header setter utilities are deprecated; use event.res.headers.set(name, value).
toNodeListener is deprecated; migrate to toNodeHandler.
useBase is deprecated; migrate to withBase.
New APIs and options 2
The router is integrated into H3; use new H3() instead of createApp() and createRouter().
readBody parses JSON or URL-encoded requests using JSON.parse or URLSearchParams.
Behavior and default changes 2
Native event.node.{req,res} is only available when the server runs in the Node.js runtime.
Middleware without a response lets later handlers run; if none respond, H3 returns a 404.
Fixes and other changes 1
Check handleCors's return value and return early when it handled the request.
h3 15 changes
Security 5
h3: Double Decoding in
serveStaticBypassesresolveDotSegmentsPath Traversal Protection via%252e%252eh3: SSE Event Injection via Unsanitized Carriage Return (
\r) in EventStream Data and Comment Fields (Bypass of CVE Fix)h3 has a Path Traversal via Percent-Encoded Dot Segments in serveStatic Allows Arbitrary File Read
h3 has a Server-Sent Events Injection via Unsanitized Newlines in Event Stream Fields
h3 v1 has Request Smuggling (TE.TE) issue