Skip to content

[beta notes] #4544

Description

@pi0

This beta release focuses on security hardenings, bug fixes, better observability, and a more reliable development experience.

Most of what is new comes from a large sweep of 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

📦 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)

This now covers vite itself, storage drivers, database client libraries, and the Cloudflare dev runtime.

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)

🧭 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)
  • GET routes automatically answer HEAD requests.
  • New cors rule replaces manual CORS wiring: { "/api/**": { cors: true } }.
  • basicAuth route 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 idleTimeout to detect half-open connections, application-level ping/pong hooks and peer.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

⚡ 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 ?import requests remain handled by Vite.
  • Static presets no longer create an unnecessary server bundle.
  • Import any file as bytes or text in the server bundle: (#4431)
    import logo from "./logo.png" with { type: "bytes" }; // Uint8Array
    import readme from "./README.md" with { type: "text" }; // string

☁️ Presets

  • Cloudflare: local development now uses Miniflare/workerd directly, with bindings available on the request event. Nitro offers to install miniflare when first needed. See the Nitro Cloudflare guide. (#4338)
  • Vercel: set vercel.immutableStaticFiles: true to 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)

🔒 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/tasks and /_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 ETag and Last-Modified, byte ranges, optional Cache-Control, and additional path-traversal hardening.

⚠️ After you upgrade

Routing

  • Replace basicAuth route 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 cors rule where needed: { "/api/**": { cors: true } }.

  • Update renamed types when convenient: NitroRouteConfig and NitroRouteRules are deprecated aliases for RouteRuleConfig and NormalizedRouteRules. The old names are still exported from nitro/types.

Review your caching configuration

The upgrade from ocache 0.1 to 0.3 introduces safer defaults for defineCachedHandler, defineCachedFunction, and cache route rules:

  • swr now defaults to false, so expired entries are refreshed before returning. Set swr: true to keep background revalidation. The swr route-rule shortcut already does this.
  • Query parameters are ignored by default. Set allowQuery: true or list the parameters that should affect the cache key.
  • Cookies are removed from cached requests and responses unless listed in allowCookies; responses containing Set-Cookie are not cached.
  • GET and HEAD now 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.

Dependencies

If you use a feature that needs an extra package, Nitro now prompts to install it instead of shipping it as a peer dependency. Add it to your project when prompted (or ahead of time) — this includes vite, storage drivers, database client libraries and miniflare.


📦 Major dependency updates

Package From To Release notes
h3 2.0.1-rc.22 ^2.0.1-rc.29 rc.23rc.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 rc.22 → rc.29 — routing, hardening and new utils

  • New route rules engine (#1524, docs) — what Nitro's route rules now build on.
  • New request features: QUERY method support, automatic HEAD matching for GET routes, requireContentType and appendAcceptQuery, formdata in readBody, async validation in defineValidatedHandler, an onDispose hook, and returning an EventStream directly from handlers. See the h3 request utilities.
  • Sessions: default SameSite=Lax cookie, PBKDF2 seal iterations raised to 8192, and opt-in idleTimeout for 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 html template tag, hop-aware x-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 CORS Vary/credential handling. See the h3 security utilities.

srvx 0.11 → 0.12 — static serving and the Node adapter

  • Static files: security hardening, ETag + Last-Modified conditional requests, byte-range support, and opt-in Cache-Control via maxAge/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, HEAD bodies are discarded, client aborts destroy the body stream, and unhandled handler errors answer 500.
  • New: body size limit helpers via srvx/body-limit (docs).
  • ⚠️ Subpath exports were renamed to *Middleware / *Plugin (#278).

rou3 0.8 → 0.9 — matcher

  • Route pattern overlap utilities (#183) and regExpToRoute() to convert PCRE regex back to a route pattern (#188).
  • findAllRoutes aligned with findRoute and compiled matchAll, with same-node siblings ordered by specificity.

db0 0.3 → 0.4 — connectors

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), prisma and libsql-core connectors, plus a Kysely integration.
  • Database capabilities metadata and exposed connector name.
  • Tracing channel support (feeds the new tracing logger).
  • ⚠️ Drizzle upgraded to v1, with schema parameter support and updated postgres/mysql connectors.

ocache 0.1 → 0.3 — caching

See the Nitro caching guide and ocache migration guide.

New in this line, beyond the default changes listed above:

  • Layered and binary-friendly storage: composeStorage for fast + persistent backends, native binary payloads without base64, binary function results, and createBlobStorage.
  • Latency and background work: opt into stream to serve a cache fill while it is still buffering, and waitUntil for background tasks.
  • New hooks and options: getMaxAge (per-entry TTL), serialize, shouldCache, async validate, sendCacheControl: false, and .expire() / .invalidate() / .resolveKeys() on cached handlers.
  • Automatic headers: Vary emission for your varies config and an x-cache status header (hit / stale / revalidated / miss).
  • Runtime-independent hashing: deterministic SHA-256 based hashing with stronger collision protection and no runtime dependencies.

env-runner 0.1 → 0.2 — Cloudflare dev runtime

See the Nitro Cloudflare guide.

  • ⚠️ Runtime dependencies are now explicit — Nitro offers to install miniflare the first time Cloudflare local development needs it.

unctx 2.5 → 3 — 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 AsyncLocalStorage using WeakRef.
  • ⚠️ ESM-only dist; unplugin is now an optional peer dependency.

unwasm 0.5 → 0.6 — WASM imports

See the unwasm documentation.

  • ⚠️ webassemblyjs replaced with a built-in WASM parser (#104) — fewer dependencies and a lighter install.
  • mlly moved to dev dependencies, knitwork utils inlined, and rolldown added to the plugin build suite.

Other notable bumps

Package From To Why it matters
crossws ^0.4.6 ^0.4.12 WebSocket liveness, backpressure, pub/sub backplane (see above)
unstorage 2.0.0-alpha.7 ^2.0.0-alpha.9 Optional peer deps removed (drivers install on demand), opt-in atomic fs writes, redis setItems, S3 prefix/pagination fixes, web-API storage server
nf3 ^0.3.17 ^0.3.23 Externals tracing: pnpm nested dependencies, transitive traceInclude deps, traceIncludeRoots, parallelized file copies
rolldown ^1.1.0 ^1.2.4 Default builder
vite ^8.0.16 ^8.2.1 Vite 7 is still supported (^7 || ^8)
@cloudflare/workers-types ^4 ^5 Cloudflare preset typings
@cloudflare/workers-utils ^0.23 ^0.33 Cloudflare preset build utils
wrangler / miniflare 4.99 / 4.x 4.124 / ^4 Cloudflare local dev and deploy
@netlify/functions ^5 ^6 Netlify preset
@netlify/edge-functions ^3 ^4 Netlify Edge preset
@vercel/queue ^0.3 ^0.4 Vercel queues
zephyr-agent ^0.2 ^1.2 Zephyr deploy integration
@scalar/api-reference ^1.59 ^1.65 Built-in OpenAPI / API reference UI
typescript ^6 ^7 Nitro now type-checks with TypeScript 7 (tsc); the @typescript/native-preview dev dependency is gone

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.


Full changelog

compare changes

🚀 Enhancements

🔥 Performance

  • build: Only cross-resolve internal aliases (#4371)
  • dev: Cache sourcemap consumer per bundle in error handler (#4454)

🩹 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)
  • vite: Respect apply and dedupe when registering nitro modules from vite plugins (#4430)
  • vite: Route asset-tagged requests to opaque catch-alls in dev (#4467)
  • vite: Keep ?import module requests on vite in dev (#4453)
  • vite: Subscribe rollup:reload to hot-reload after updateConfig (#4503)
  • presets: Keep srvx/body-limit out of the bare srvx alias (#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 with key (#4520)
  • dev: Await worker shutdown before replacing it (#4506)
  • vite: Skip server bundle for static presets (#4509)
  • vite: Serialize dev worker reloads (#4541)
  • vite: Clear module runner cache before dev worker reload (#4473)

💅 Refactors

  • Replace deprecated tsconfck with get-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)

📖 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)

📦 Build

  • Point root types to published declaration (#4347)
  • Remove ofetch from deps (f9091c14)
  • Re-export FastResponse and srvx types (#4499)
  • Externalize cjs declarations (f930cda7)

🌊 Types

  • Export missing h3 types from runtime (#4378)
  • Use CachedFunction return type for defineCachedFunction (#4377)

✅ 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

  • Improve actions workflows (#4388)
  • Run pkg.pr.new after lint (11b4761a)

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)
  • cloudflare: Omit worker entry from wrangler.json for static builds (#4255)
  • vercel: Strip trailing slash from prerendered route overrides (#4412)
  • netlify: Enable code-splitting for the netlify-edge preset (#4525)
  • vercel: Preserve relative function symlinks (#4490)
  • vercel: Use SameSite=Lax for skew protection cookie (#4422)

❤️ Contributors

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions