Note
Thi release focuses on security hardenings, bug fixes, better observability, and a more reliable development experience.
Many of new improvements are from major dependency upgrades (h3, srvx, rou3, ocache, db0, env-runner, unctx and unwasm) plus the work in Nitro to adopt them. The sections below group the changes by what they mean for your app.
🚀 What’s new
🧭 Routing and route rules
Nitro migrated to the new route rules engine from h3, backed by rou3 v0.9. See the Nitro routing guide and h3 route rules guide. (#4411)
- Rules are matched on the canonical path, with sibling routes ordered by specificity. (#4396)
GETroutes automatically answerHEADrequests.- New
corsrule replaces manual CORS wiring:{ "/api/**": { cors: true } }. basicAuthroute rules are replaced by middleware (see After you upgrade).
💾 Caching
defineCachedHandler, defineCachedFunction and cache route rules now run on ocache v0.3 (up from 0.1), which brings safer defaults, bounded memory and several new capabilities. Please review your caching configuration — defaults changed. See Review your caching configuration and the Nitro caching guide.
🗄️ Database
Nitro now uses db0 v0.4. Database client libraries are passed explicitly to connectors; Nitro handles this for configured connectors and prompts to install what is missing. New in this line: neon, prisma and libsql-core connectors, Kysely integration, database capabilities metadata, and tracing channel support. See the Nitro database guide, db0 connectors, and db0 integrations.
🔌 WebSockets
WebSocket support moves to crossws 0.4.12 (from 0.4.6), which adds a batch of features usable from Nitro WebSocket handlers. See the Nitro WebSocket guide.
- Liveness: universal
idleTimeoutto detect half-open connections, application-level ping/pong hooks andpeer.ping(). (#201, #202) - Backpressure:
peer.bufferedAmount(docs) and opt-in subprotocol negotiation. (#195, #203) - Pub/sub: a sync backplane to share channels across instances (docs), plus auth and context support. (#192, #112)
🔭 Observability and tracing
- Native platform traces: Nitro sends spans to Vercel session traces and Cloudflare Workers Observability without bundling the OpenTelemetry SDK. (#4355, #4413)
- Built-in tracing logger: enable
tracingChannelandexperimental.tracingLoggerto log completed h3, srvx, unstorage, db0 and other spans in development and production — without additional dependencies. (#4406)
🔒 Security
- h3 has undergone several rounds of security hardening audits (path normalization, forwarded headers, host header handling, cookies, CORS, basic auth, JSON-RPC, session sealing).
- Development task endpoints (
/_nitro/tasksand/_nitro/tasks/:name) now accept only local requests. This prevents remote clients with access to the dev server from listing or invoking tasks. (#4389) - Cached responses no longer replay cookies by default.
- Better static file responses: conditional requests with
ETagandLast-Modified, byte ranges, optionalCache-Control, and additional path-traversal hardening.
⚡ Faster and more reliable
- Improved alias resolution, development sourcemaps, request middleware, and logging.
- Development worker reloads are serialized and cleanly awaited, stale module caches are cleared, (vite) aliases apply in the correct order, base paths are respected, and
?importrequests remain handled by Vite. - Static presets no longer create an unnecessary server bundle.
📁 Import any file as bytes or text
In server bundle: (#4431)
import logo from "./logo.png" with { type: "bytes" }; // Uint8Array
import readme from "./README.md" with { type: "text" }; // string📦 No more peer dependencies
Nitro no longer has any peer dependencies. Features that need an extra package (a builder, a preset, a storage driver, a database connector) resolve it from your project, and Nitro prompts to install anything missing. In CI, missing packages are installed automatically. Existing projects need no changes when the required packages are already installed. (#4542, #4543)
Nitro also validates the version of what it finds and warns when an installed package is outside the supported range. Supported builders are vite@^7 || ^8, rollup@^4 and rolldown@>=1.0.0. (87219b2)
Leaner install
Alongside dropping peer dependencies, several packages were removed from Nitro entirely: tsconfck (replaced by get-tsconfig), magic-string, uncrypto, serve-placeholder, edge-runtime, @types/http-proxy and @types/node-fetch. ofetch is no longer a runtime dependency, and rou3 is now a direct dependency instead of being pulled in indirectly.
☁️ Presets
- Cloudflare: local development now uses Miniflare/
workerddirectly, with bindings available on the request event. Nitro offers to installminiflarewhen first needed. See the Nitro Cloudflare guide. (#4338) - Vercel: set
vercel.immutableStaticFiles: trueto emit content-hashed static files with immutable caching. See the Nitro Vercel guide. (#4432) - Netlify Edge: keeps dynamic imports lazy, reducing cold-start work for lazy handlers and deferred WASM initialization. (#4525)
⚠️ Migration
Routing
-
Replace
basicAuthroute rules with middleware.import { defineHandler } from "nitro"; import { basicAuth } from "nitro/h3"; export default defineHandler({ middleware: [basicAuth({ username: "admin", password: "supersecret" })], handler: (event) => `Hello, ${event.context.basicAuth?.username}!`, });
To protect multiple routes, register route-scoped middleware or add it under
middleware/. -
Use the new
corsrule where needed:{ "/api/**": { cors: true } }. -
Update renamed types when convenient:
NitroRouteConfigandNitroRouteRulesare deprecated aliases forRouteRuleConfigandNormalizedRouteRules. The old names are still exported fromnitro/types.
Review your caching configuration
The upgrade from ocache 0.1 to 0.3 introduces safer defaults for defineCachedHandler, defineCachedFunction, and cache route rules:
swrnow defaults tofalse, so expired entries are refreshed before returning. Setswr: trueto keep background revalidation. Theswrroute-rule shortcut already does this.- Query parameters are ignored by default. Set
allowQuery: trueor list the parameters that should affect the cache key. - Cookies are removed from cached requests and responses unless listed in
allowCookies; responses containingSet-Cookieare not cached. GETandHEADnow use separate cache entries.- Cache keys now include the request authority, and undeclared request headers are hidden from handlers.
- Cache resolution has a new 30-second timeout (
maxResolveTime), and memory storage is limited by bytes.
See the ocache migration guide for details.
📦 Major dependency updates
| Package | From | To | Release notes |
|---|---|---|---|
h3 |
2.0.1-rc.22 |
^2.0.1-rc.29 |
rc.23 … rc.29 |
srvx |
^0.11.16 |
^0.12.7 |
v0.12.0 |
rou3 |
^0.8.1 |
^0.9.2 |
v0.9.0 |
db0 |
^0.3.4 |
^0.4.0 |
v0.4.0 |
env-runner |
^0.1.12 |
^0.2.0 |
v0.2.0 |
ocache |
^0.1.5 |
^0.3.0 |
v0.2.0, v0.3.0 — crosses two lines |
unctx |
^2.5.0 |
^3.0.1 |
v3.0.0 |
unwasm |
^0.5.3 |
^0.6.0 |
v0.6.0 |
h3
- New route rules engine (#1524, docs) — what Nitro's route rules now build on.
- New request features:
QUERYmethod support, automaticHEADmatching forGETroutes,requireContentTypeandappendAcceptQuery,formdatainreadBody, async validation indefineValidatedHandler, anonDisposehook, and returning anEventStreamdirectly from handlers. See the h3 request utilities. - Sessions: default
SameSite=Laxcookie, PBKDF2 seal iterations raised to 8192, and opt-inidleTimeoutfor sliding expiration. See the h3 session example. - Performance: precomposed middleware chains, streaming body-limit enforcement, faster path normalization and cookie parsing.
- Security: escaped interpolation in the
htmltemplate tag, hop-awarex-forwarded-*handling, host header no longer steers the synthesized URL, stricter percent-decoding and canonical-path checks in static serving, hardened basic auth and JSON-RPC, and safer CORSVary/credential handling. See the h3 security utilities.
srvx
- Static files: security hardening,
ETag+Last-Modifiedconditional requests, byte-range support, and opt-inCache-ControlviamaxAge/immutable. (#252, #269, #273, #275) - Performance: the middleware chain is precomposed at construction time and stdout writes are batched with a cached timestamp.
- Node adapter correctness: bridged responses stream instead of buffering, hop-by-hop headers are stripped,
HEADbodies are discarded, client aborts destroy the body stream, and unhandled handler errors answer500. - New: body size limit helpers via
srvx/body-limit(docs). ⚠️ Subpath exports were renamed to*Middleware/*Plugin(#278).
rou3
- Route pattern overlap utilities (#183) and
regExpToRoute()to convert PCRE regex back to a route pattern (#188). findAllRoutesaligned withfindRouteand compiledmatchAll, with same-node siblings ordered by specificity.
db0
See the Nitro database guide and the db0 connector reference.
⚠️ Connectors require the client library to be passed explicitly. Nitro does this for connectors you configure, and prompts to install the missing package.- New
neon(serverless postgres),prismaandlibsql-coreconnectors, plus a Kysely integration. - Database
capabilitiesmetadata and exposed connector name. - Tracing channel support (feeds the new tracing logger).
⚠️ Drizzle upgraded to v1, withschemaparameter support and updated postgres/mysql connectors.
ocache
See the Nitro caching guide and ocache migration guide.
New in this line, beyond the default changes listed above:
- Layered and binary-friendly storage:
composeStoragefor fast + persistent backends, native binary payloads without base64, binary function results, andcreateBlobStorage. - Latency and background work: opt into
streamto serve a cache fill while it is still buffering, andwaitUntilfor background tasks. - New hooks and options:
getMaxAge(per-entry TTL),serialize,shouldCache, asyncvalidate,sendCacheControl: false, and.expire()/.invalidate()/.resolveKeys()on cached handlers. - Automatic headers:
Varyemission for yourvariesconfig and anx-cachestatus header (hit/stale/revalidated/miss). - Runtime-independent hashing: deterministic SHA-256 based hashing with stronger collision protection and no runtime dependencies.
env-runner
See the Nitro Cloudflare guide.
⚠️ Runtime dependencies are now explicit — Nitro offers to installminiflarethe first time Cloudflare local development needs it.
unctx (async context)
- Defaults to the built-in
AsyncLocalStorage. - Transform moved to oxc, skips files without
await, and precomputes line offsets. - Fixes an instance leak via
AsyncLocalStorageusingWeakRef.
unwasm (WASM support)
See the unwasm documentation.
⚠️ webassemblyjsreplaced with a built-in WASM parser (#104) — fewer dependencies and a lighter install.
Full changelog
🚀 Enhancements
- Experimental tracing logger (#4406)
- routing: Migrate route rules to h3-rules (#4411)
- build: Support
bytesandtextimport attributes (#4431) ⚠️ Migrate toh3/rules(f70163c3)- Prompt to install storage driver dependencies (89bda739)
- Migrate env-runner to 0.2 with explicit deps (5060305f)
- Upgrade to db0 0.4 (d435e8c9)
- vite: Import
viteon demand from the user project (#4543)
🔥 Performance
- build: Only cross-resolve internal aliases (#4371)
- dev: Cache sourcemap consumer per bundle in error handler (#4454)
- app: Compose the middleware chain once instead of per request (#4559)
🩹 Fixes
- vite: Handle explicit public asset dirs (7765bcb7)
- vite: Close env runner during Vite environment cleanup (#4362)
- config: Detect
vite.config.c[jt]s(#4363) - rolldown: Disable built-in tsconfig loader (#4369)
- vite: Generate nitro types in vite builder (#4387)
- dev: Restrict /_nitro/tasks endpoint to local requests (#4389)
- vite: Respect bun/deno export conditions in dev server (#4397)
- route-meta: Add order:pre to route-meta plugin hooks (#4316)
- Match route rules on canonical path (#4396)
- externals: Force-trace named traceDeps to fix pnpm nested deps (#4391)
- externals: Only force-trace observed native imports (#4420)
- vercel: Use
SameSite=Laxfor skew protection cookie (#4422) - vite: Respect
applyand dedupe when registering nitro modules from vite plugins (#4430) - vite: Route asset-tagged requests to opaque catch-alls in dev (#4467)
- vite: Keep
?importmodule requests on vite in dev (#4453) - vite: Subscribe
rollup:reloadto hot-reload afterupdateConfig(#4503) - presets: Keep
srvx/body-limitout of the baresrvxalias (#4538) - externals: Skip bare scopes as unresolvable (69c36aa8)
- build: Namespace virtual module ids in sourcemap sources (f135ec84)
- vite: Always remove deprecated
inlineDynamicImports(23c93b07) - vite: Make dev middleware Vite-internal prefix checks base-aware (#4540)
- vite: Pass aliases as ordered entries so specific keys win (#4537)
- rollup: Emit import attributes with the
withkey (#4520) - netlify: Enable code-splitting for the netlify-edge preset (#4525)
- vercel: Preserve relative function symlinks (#4490)
- dev: Await worker shutdown before replacing it (#4506)
- cloudflare: Omit worker entry from wrangler.json for static builds (#4255)
- vercel: Strip trailing slash from prerendered route overrides (#4412)
- vite: Skip server bundle for static presets (#4509)
- vite: Serialize dev worker reloads (#4541)
- vite: Clear module runner cache before dev worker reload (#4473)
- config: Resolve default server assets dir from
serverDir(#4562) - routing: Respect
baseURLfor single catch-all routes (#4561) - routing: Serialize route-scoped middleware as plain handlers (#4558)
- vercel: Correct ISR route rewrite query preservation and decoding (#4409)
- presets: Call runtime
closehooks on server shutdown (#4574) - build: Count each output file once in the size report (#4568)
- build: Pass the real request to node format handlers (e5de9849)
- cloudflare: Correctly traverse baseURL segments when computing assets directory (#4257)
- rollup: Escape dynamic route segments in chunk names (#4508)
- vercel, netlify, edgeone: Expand
**anywhere in redirect and proxy targets (066510fd) - cloudflare: Do not rewrite createRequire or node imports inside strings (#4535)
- vercel: Prevent caching missing public assets (#4474)
- storage, database: Import connector libs from their real specifier (8157e00b)
- deps: Auto-install in agent and non-tty environments (a28ca29f)
💅 Refactors
- Replace deprecated
tsconfckwithget-tsconfig(#4367) - build: Disable rolldown internal export minification (#4368)
- deno: Use default node handler for serveStatic (#4398)
- Improve logging plugin responsiveness (f3a1aa6d)
- deps: Import optional deps on demand from the user project (#4542)
- dep: Version validation (87219b2a)
- Use node hash (923f3c28)
- types:
⚠️ Remove typed fetch (#4572) ⚠️ Remove auto imports (#4573)⚠️ Remove type generation (#4577)
📖 Documentation
- vercel: Fix queues examples for nitro v3 api (#4374)
- Fix grammer issue in landing (#4382)
- Use variable font weight range for geist (#4383)
- Update zerops provider docs (#4380)
- Add defineNitroPlugin to migration guide (#4400)
- examples: Add takumi og image example (#4421)
- Use event.url.pathname in lifecycle hook examples (#4442)
- Fix link navigation (#4444)
- Clarify database connection options shape (#4465)
- Update to last undocs (#4524)
- Add missing redirects (16ff2809)
- Update landing (46a6fcaf)
- List supported configuration file names (#4517)
- Improvements (#4426)
- Document
minify: falsefor debugging workers (#4452) - Clarify route-scoped middleware example path (#4445)
📦 Build
- Point root types to published declaration (#4347)
- Remove ofetch from deps (f9091c14)
- Re-export
FastResponseand srvx types (#4499) - Externalize cjs declarations (f930cda7)
🌊 Types
- Export missing h3 types from runtime (#4378)
- Use
CachedFunctionreturn type fordefineCachedFunction(#4377) - vite: Use named types for fetchable dev environment (78437e1c)
- config: Map builtin driver and connector options (#4571)
- Widen
RollupConfig.pluginsto accept rolldown-typed plugins (#4483)
✅ Tests
- public-assets: Cover node reader path resolution and traversal safety (65d275b7)
- Add local wasm fixture (af70f2d7)
- Bump bundle sizes (a2528959)
- Silent logs (96607689)
🤖 CI
Preset Changes
- cloudflare: Use env-runner/miniflare for local dev and update docs (#4338)
- vercel: Use reflinks for custom function dirs (#4373)
- vercel: Export tracing channels messages as otlp spans (#4355)
- cloudflare: Bridge tracing channel events to observability custom spans (#4413)
- Update winterjs (a1cac7d7)
- vercel: Support immutable static files (#4432)
- vercel: Do not generate observability functions with fully prerendered routes (#4497)
- aws-lambda: Switch to srvx (#4056)
❤️ Contributors
- Brenley Dueck (@brenelz)
- Pooya Parsa (@pi0)
- Ilya Butenko (@ilya9933)
- Reza Rahemtola (@RezaRahemtola)
- Jason El-Massih (@jel-massih)
- Maxim Lepekha
- Jonas Thelemann
- Ryan Conceicao (@ryoid)
- Yi Zhan (@Steve0x2a)
- Birk Skyum (@birkskyum)
- Schplitt (@schplitt)
- Rihan Arfan @RihanArfan)
- Thribhuvan
- Daniel Roe (@danielroe)
- Dawit (@oneminch)
- Andrew Barba (@AndrewBarba)
- Jake
- Tarik Ermis
- Leonid G.
- Shree Bohara (@ShreeBohara)
- N0liu (@n0liu)
- Vittorio Esposito
- Abeer0 (@iiio2)
- BTF Kabir (@BTF-Kabir-2020)
- Kane Wang (@yeecord)
- UNUSDON
- Justin White (@kyjus25)
- Vanshika Rana (@Vanshika-Rana)
- Ulrich Stark (@ulrichstark)
- Bernd Storath (@kaaax0815)
- Luis Fernando Ramírez Rivas (@Fernando-droidx)
- Winston Crooker
- Pavel Dubovitsky (@p-dubovitsky)
- Luke Nelson
- Hugo (@HugoRCD)
- Lachlan Heywood (@lachieh)
- Alexander Lichter (@TheAlexLichter)
- Muhammad Naufal Kateni (@NaufalK25)