Skip to content

v2.11.0

Compare
Choose a tag to compare
@pi0 pi0 released this 04 Mar 19:05
· 53 commits to v2 since this release

💬 Release Discussion

🌟 What is new?

🟢 Better Errors

Error handlers for both development and production environments have been rewritten (see #3002 for more details).

Powered by poppinss/youch (v4.x), you can now view beautiful error pages with stack traces in both the browser and CLI.
Nitro automatically applies source maps to error stack traces—no need to set NODE_OPTIONS="--enable-source-maps"—allowing you to pinpoint the exact file and line where an issue occurs.

Previously, Nitro conditionally rendered JSON errors based on certain user-agent headers or when requests were made to /api/*.
For more consistent behavior, any request not made from a browser (i.e., without the Accept: text/html header) will always receive a JSON response. Additionally, all production errors are now returned in JSON format.

You can still override the error handler for both development and production using the errorHandler config. If you want to fall back to the default error handler conditionally, you can simply return without handling the response (see #3085 for more details).

Additional strict security headers will be always added to error responses (#2907).

Example error in development:

image image
Example error in production
{
  "error": true,
  "url": "http://localhost:3000/",
  "statusCode": 500,
  "statusMessage": "Server Error",
  "message": "Server Error",
  "data": {
    "foo": "bar"
  }
}

🟢 Better Dev Server

Every time you run the nitro dev or nuxt dev command, Nitro creates an isolated worker thread and proxies requests from the browser to the server inside the worker using a Unix socket or a named pipe on Windows.

To improve stability and provide a better experience, the internal mechanism for creating and reloading the server and handling errors has been rewritten (see #3135 for more details).

🟢 Database Improvements

Nitro's database support, powered by db0 0.3.x, now offers improved types, better-prepared statements, better API consistency, and native node:sqlite support (#3127).

Thanks to native node:sqlite support in Node.js (>= 22.5.0) and Deno (>= 2.2), you can now use databases in both environments without external dependencies or extra configuration!

🟢 Improved baseURL Handling

For deployments that need to be served under a base URL (e.g., /admin), Nitro provides a baseURL config. When enabled, all routes and static assets will be prefixed accordingly.

Depending on the deployment platform, the build output structure may need to be adjusted. The Netlify and Stormkit presets have been updated with fixes (#2966, #2971, 5a51bf06). Additionally, we have enabled baseURL for nitro-deploys for end-to-end testing.

The new Nitro error handler also improves the user experience. If a request is made to the server without the required base URL, it will now automatically redirect (#3146).

🟢 Prerender Crawler

Nitro's prerender feature includes a crawler that scans each page to discover additional links. However, previous versions relied on regex matches, which occasionally led to false detections.

This release migrates to natemoo-re/ultrahtml for more precise link extraction (#3068).

🟢 Improved Module Resolution

Nitro has migrated to exsolve for internal module resolution. This change improves performance (up to 3x), and stability, and enforces stricter search paths (#3125).

🟢 Firebase App Hosting

Zero-config deployment support for Firebase App Hosting has been added (#2864, #2895, #2967).

🟢 Node.js Compatibility for edge and Deno v2

The Nitro server can be deployed to any runtime and platform. We built unenv and integrated it into Nitro so that if your code or any library you use requires Node.js-specific features such as Buffer, process.env, or setImmediate, they can continue working through automatically injected lightweight polyfills.

Thanks to efforts like WinterCG, the ecosystem has shifted towards using more web standards that work in any JavaScript runtime.
However, some Node.js features remain difficult to replace, such as node:async_hooks, node:crypto, node:net, and even process.env, which plays a de facto standard role while standards for JavaScript servers continue to evolve.

Edge runtimes (Cloudflare Workers, Deno Deploy, Netlify Edge, and Vercel Edge) are built on top of the V8 engine and traditionally lacked support for Node.js APIs and globals. Thankfully, both Deno (v2) and Cloudflare (workerd) have made significant efforts to support Node.js APIs in their edge runtimes. You can check the status using the unofficial platform-node-compat tests.
This improvement makes Nitro's support for edge runtimes faster, smaller, and more capable. Features like AsyncLocalStorage, which cannot be simply polyfilled, benefit from these new APIs.

While edge platforms have (partially) implemented Node.js APIs, we still need to polyfill any unsupported features using unenv.
Unenv v2 is a major rework with all Node.js modules rewritten as ESM polyfill modules, ensuring full coverage of known exports from the latest Node.js LTS release. With Unenv v2, we can create hybrid/native Node.js polyfills that combine native runtime support with polyfills at the module export level (used for cloudflare presets).

Enabling Node.js compatibility:

For Cloudflare deployments, we have also added an experimental new method to enable Node.js compatibility, which will be enabled by default in future releases.
Please note that creating a wrangler.toml file or using deployConfig flag, disables Cloudflare dashboard features, and variables set from the dashboard will be lost.

Opt-in to cloudflare deploy config
// Nitro
export default defineNitroConfig({
  compatibilityDate: "2025-03-01",
  cloudflare: { nodeCompat: true, deployConfig: true }
});

// Nuxt
export default defineNuxtConfig({
  compatibilityDate: "2025-03-01",
  nitro: { cloudflare: { nodeCompat: true, deployConfig: true } }
});

📦 Dependency Upgrades

Several dependencies across unjs have been updated, focusing on performance improvements and an ESM-only dist to reduce install size. This has already reduced the package size by approximately ~28MB, with further reductions planned as we phase out dual-format published packages.

  • unenv upgraded to v2 (full rewrite).
  • db0 upgraded to v0.3 (ESM-only, native node:sql, improvements).
  • ohash upgraded to v2 (#3114) (ESM-only, native node:crypto support, much faster)
  • unimport upgraded to v4 (improvements).
  • pathe upgraded to v2 (improvements).
  • untyped upgraded to v2 (ESM-only, less install size).
  • c12 upgraded to v3 (ESM-only).
  • cookie-es upgraded to v2 (ESM-only).
  • esbuild upgraded to v0.25.
  • chokidar upgraded to v4 (#3113).

📝 Other Changes

Note

164 commits, 168 files with 8,341 additions, and 5,476 deletions from 33 contributros since last 2.x release.
Changelog below is subset of changes (compare all changes)

🚀 Enhancements

  • cloudflare-durable: Allow redirect fetch to durable object (#3048)
  • openapi: Allow $global.components in defineRouteMeta (#2921)
  • Support unenv: [] as array of presets in config (#3141)
  • Add build:before hook (#3142)

🩹 Fixes

  • Allow patching globalThis.fetch (#3009)
  • Update dynamic-require plugin to match new webpack chunk format (#2947)
  • Unique imports for server-handlers-meta (#2945)
  • Auto import multiple levels of nested directories in utils/ (#2953)
  • Scan route files with other characters in param name (#2872)
  • Add NitroApp type export to main subpath for backward compatibility (#2875)
  • Run nitro modules before createUnimport (#3016)
  • Respect configured workspaceDir (#3148)
  • config: Use static preset if static: true config is set (#2860)
  • config: Avoid serialization warning when primitives have prototype changed (#2902)
  • config: Normalize route rules with leading slash (#2978)
  • config: Clone preset object (#2983)
  • config: Make sure serialized storage options are not modified (#2977)
  • externals: Respect importer path for resolving (#3137)
  • timing: Silent in test (f8cb7620)
  • server-assets: Include files without extension by default (#2995)
  • rollup: Remove unenv/npm/consola polyfill (57bd74bd)
  • rollup: Resolve unenv paths with expected version (#3073)
  • cache: Polyfill event.waitUntil for cachedEventHandler (#3083)
  • types: Deduplicate aliases (#3120)
  • node-cluster: Create dedicated chunk for worker (#2894)
  • azure-functions: Pass body to the context as-is (#2965)
  • cloudflare: Add known cloudflare: externals (#2976)
  • netlify: Avoid second bundling (#3046)
  • deno-deploy: Always externalize node: imports (a9fc2673)

💅 Refactors

  • Use node-mock-http for local fetch (#3069)
  • Split legacy error utils (#2982)
  • Improve env expansion regex (#3037)
  • Use toExports util from unimport (#3059)
  • Replace @rollup/pluginutils with unplugin-utils (#3075)
  • Remove extra tag in logs (#3143)
  • vercel, netlify: Hide ISR warning in tests (cc564996)
  • cloudflare: Sync wrangler types with upstream (#3054)
  • cloudflare: Split legacy presets (834dd483)

📖 Documentation

  • config: Document compatibilityDate option (#2941)
  • config: Document openAPI.production option (#2940)
  • guide: Add Deno to installation methods (#3010)
  • config: Update openAPI section (#2869)
  • cache: Add return type constraint for cached functions (#3097)
  • netlify: Add deprecated warning for netlify-builder preset (#2972)
  • cloudflare: Remove note about pages and wrangler.toml support (#3117)
  • vercel: Update docs (#3149)
  • database: Update postgresql example (#3092)
  • Link route meta to openAPI (#3082)
  • Minor tweaks (#2896, #2915, #2931, a0b6ad8b, #2963, #2916, #3039, #3038, #2987, #3124, #3116)

🌊 Types

  • Fix type for event.$fetch (#2913)

❤️ Contributors