# What changed in h3

> 64 changes in h3 1 to 2 from its official release notes, upgrade guides and advisories: 28 breaking, 25 deprecations, 6 security, 2 new APIs and options. Each one cited. Sources checked 2026-10-20. HTML: https://unstale.sh/npm/h3/

To see which of these apply to a repository, run `npx @unstale/cli init` in it.

## h3 2

### Breaking changes

- The App type export migrates to H3. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- app.resolve(path) has been removed. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- app.use("/path", handler) now matches only /path; use /path/** to match subpaths. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Array paths and arrays of handlers are no longer supported; use multiple app.use() calls. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- The AppOptions type export migrates to H3Config. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- createEvent was removed; use the Node.js adapter toNodeHandler(app). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- CreateRouterOptions migrates to RouterOptions. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Lazy handlers must be wrapped with defineLazyEventHandler instead of passing a factory directly to app.use. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- H3 v2 is ESM-only; latest Node.js versions can still load it with require("h3") through require(esm). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Handler event.path now includes the full path without omitting prefixes; withBase can create a prefixed app. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- event.web is renamed to event.req, which is an instance of the web Request interface. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- getRequestProtocol no longer trusts x-forwarded-proto by default; opt in with xForwardedProto behind a trusted proxy or CDN. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- H3Headers migrates to the native Headers type. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- H3Response migrates to the native Response type. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- H3 uses standard web Headers for utilities, and header values are always strings. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- isEventHandler was removed; any function can be an event handler. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Replace sendIterable(event, value) with return iterable(value). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- MIMES has been removed. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Replace sendNoContent(event) or return null with return noContent(). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- H3 v2 requires Node.js >= 20.19. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- The NodeListener type export migrates to NodeHandler. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Replace sendProxy(event, target) with return proxy(event, target). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Replace sendRedirect(event, location, code) with return redirect(location, code). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Body utilities return empty values instead of throwing when a request has no body, such as for GET requests. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Handlers should explicitly return response bodies or throw errors; H3 detects returned text, JSON, streams, and web Responses. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- RouteNode migrates to RouterEntry. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- A router handler that returns no response now produces a simple 200 with empty content. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- The signature changes from router.add(path, method) to router.add(method, path). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)

### Security

- Native request.json and readBody no longer use destr; filter and sanitize user data to avoid prototype poisoning. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)

### Deprecations

- Response header append utilities are deprecated; use event.res.headers.append(name, value). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- createApp and createRouter are deprecated; migrate to new H3(). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- createError and H3Error are deprecated; migrate to HTTPError. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- createEventStream is deprecated; migrate to new EventStream(event). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- eventHandler and defineEventHandler are deprecated; migrate to defineHandler or use a function directly. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- defineNodeListener is deprecated; migrate to defineNodeHandler. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- event.headers is deprecated; use event.req.headers. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- event.method is deprecated; use event.req.method. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- event.path is deprecated; use event.url.pathname + event.url.search. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- fromNodeMiddleware is deprecated; migrate to fromNodeHandler. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- getHeader and getRequestHeader are deprecated; use event.req.headers.get(name). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- getHeaders and getRequestHeaders are deprecated; use Object.fromEntries(event.req.headers.entries()). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- getMethod is deprecated; use event.req.method. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- getRequestPath is deprecated; use event.url.pathname. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- getResponseHeader and getResponseHeaders are deprecated; use event.res.headers.get(name). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Response status utilities are deprecated; use event.res.status and event.res.statusText. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- isError is deprecated; migrate to HTTPError.isError. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- lazyEventHandler is deprecated; migrate to defineLazyEventHandler. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Form-data body utilities are deprecated; use event.req.formData(). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- readRawBody is deprecated; use event.req.text() or event.req.arrayBuffer(). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- removeResponseHeader and clearResponseHeaders are deprecated; use event.res.headers.delete(name). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- router.use(path, handler) is deprecated; use router.all(path, handler) instead. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Response header setter utilities are deprecated; use event.res.headers.set(name, value). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- toNodeListener is deprecated; migrate to toNodeHandler. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- useBase is deprecated; migrate to withBase. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)

### New APIs and options

- The router is integrated into H3; use new H3() instead of createApp() and createRouter(). (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- readBody parses JSON or URL-encoded requests using JSON.parse or URLSearchParams. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)

### Behavior and default changes

- Native event.node.{req,res} is only available when the server runs in the Node.js runtime. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)
- Middleware without a response lets later handlers run; if none respond, H3 returns a 404. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)

### Fixes and other changes

- Check handleCors's return value and return early when it handled the request. (2.0.0) — [upgrade guide](https://h3.dev/raw/migration)

## h3 1

### Security

- h3: Double Decoding in `serveStatic` Bypasses `resolveDotSegments` Path Traversal Protection via `%252e%252e` (1.15.9) — [security advisory](https://github.com/advisories/GHSA-72GR-QFP7-VWHW)
- h3: SSE Event Injection via Unsanitized Carriage Return (`\r`) in EventStream Data and Comment Fields (Bypass of CVE Fix) (1.15.9) — [security advisory](https://github.com/advisories/GHSA-4HXC-9384-M385)
- h3 has a Path Traversal via Percent-Encoded Dot Segments in serveStatic Allows Arbitrary File Read (1.15.6) — [security advisory](https://github.com/advisories/GHSA-WR4H-V87W-P3R7)
- h3 has a Server-Sent Events Injection via Unsanitized Newlines in Event Stream Fields (1.15.6) — [security advisory](https://github.com/advisories/GHSA-22CC-P3C6-WPVM)
- h3 v1 has Request Smuggling (TE.TE) issue (1.15.5) — [security advisory](https://github.com/advisories/GHSA-MP2G-9VG9-F4CG)
