🏠 New home
After almost 4 years of Nitro development, it's time to evolve Nitro into a larger community and ecosystem.
- Current nitro-related repositories have been moved under the nitrojs Github org.
- Nitro documentation is hosted under a new shorter domain name: nitro.build.
nitropack
npm package is in transition to becomenitro
.
We have created a new community. You can follow Nitro updates on X via @nitrojsdev and on Bluesky via @nitro.build and feel free to join our new Discord server if you like to be involved ❤️.
🛠️ Major internal overhaul
We have made several (non-breaking) refactors in the Nitro codebase to improve long-term maintenance and structure consistency with the upcoming Nitro v3 releases.
Nitro 2.10 is a cumulative update with over 245 commits, 400+ changed files, 22,018 additions, and 13,207 deletions from 65 contributors, preparing for the next steps toward the Nitro 3 release. (see all changes)
src/*
structure is more modular (#2473), all logic related to presets moved to src/presets/*
(#2446) and internal type checks are more stricter (#2370, #2529).
Important
If you previously imported any utility from #internal/nitro/*
or nitropack/runtime/*
you should change them to #imports
to avoid issues.
📅 Compatibility date
Deployment providers introduce new features that Nitro presets can leverage, but some of them need to be explicitly opted into.
Nitro introduces a new compatibilityDate
configuration (#2511) that allows leveraging the latest platform enhancements. The Cloudflare and Netlify presets now use this feature. If this configuration is not provided, Nitro will continue using the current (v2.9) behavior for presets.
Migration:
export default defineNitroConfig({
+++ compatibilityDate: "2024-11-01",
});
🗂️ Environment-specific handlers
Each route handler in server/routes/*
and server/api/*
is always included in the server bundle for development, prerender, and production.
With the new environment-specific event handlers (#2272), you can now specify handlers that are included only under certain conditions:
.dev
(e.g.,server/api/inspect.dev.ts
): Included only in development mode..prerender
(e.g.,server/api/og_image.prerender.ts
): Included only in the prerendering stage..prod
(e.g.,server/api/health.prod.ts
): Included only in the production bundle.
This feature allows for conventionally having multiple versions of handlers (e.g., routes/admin.dev.ts
+ routes/admin.prod.ts
).
Additionally, if you add route handlers programmatically (via the handlers: []
Nitro config), you can use the env
key to specify preset-specific filters.
📍 Route groups
You can use (...)/
directory names inside server/api/*
and server/routes/*
to logically group handlers without dir being part of the path (#2664).
For example, having server/api/(group)/test.ts
, will add a /api/test
route.
📜 production mode OpenAPI support
The experimental OpenAPI feature can now be enabled in production mode (#2570).
To enable it, set openAPI.production
in the Nitro configuration.
export default defineNitroConfig({
experimental: {
openAPI: true,
},
openAPI: {
// IMPORTANT: make sure to protect OpenAPI routes if necessary!
production: "runtime", // or 'prerender'
},
});
New OpenAPI routes:
/_openapi.json
: OpenAPI v2 JSON to be used in external tools/_swagger
: built-in Swagger UI/_scalar
: built-in Scalar UI
📦 Upgraded dependencies
- Experimental WebSocket support is better with crossws@0.3 upgrade.
- Experimental Database support is better with db0@0.2 upgrade.
- Typescript support for
nitro.config.ts
and nitro modules is better with jiti@2.0.
🎛️ Preset updates
Cloudflare
cloudflare-module
preset, with compatibilityDate
config set to 2024-09-19
or later, leverages new Static Assets support to allow serving static assets directly from cloudflare CDN with low latency and without hitting the worker and occurring costs (#2800) (Note: Please beware of current limitations while this feature is in Beta).
A new (experimental) cloudflare-durable
preset is available which extends coudflare-module
to allow leveraging Cloudflare Durable objects(#2801). This allows using WebSockets with pub/sub support for use cases like chat rooms or live collaboration (check out nuxt-tiptap for a demo).
Nitro 2.10 added several hooks such as cloudflare:email
and cloudflare:queue
(#2487) and cloudflare:scheduled
, cloudflare:email
, cloudflare:queue
, cloudflare:tail
and cloudflare:trace
for cloudflare-module
preset (#2795) usable with plugins.
With the cloudflare-pages
preset, if cloudflare: { wrangler: { ... } }
is set in nitro config, Nitro will automatically merge it with wrangler.toml
in your project root during build.
Netlify
netlify
preset uses Netlify Functions 2.0 format when compatibilityDate
is set to 2024-05-07
or later (#2406). This allows streaming responses (demo), better support for hybrid rendering (prerender: true
route rule works as intended), improves background request generation, fixing bugs with set-cookie: undefined
on responses and Netlify Blobs will now work out of the box.
Previously, ISR in Nitro had been implemented on Netlify via proprietary On-Demand Builders platform primitive, which only supported "v1" Functions. Now that there's momentum around Targeted HTTP Cache Control and that Netlify supports it, we can implement ISR in Nitro via these simple, standard HTTP headers instead. With the isr
route rule, the new preset uses a new durable
cache-control directive (#2571).
All netlify presets now leverage from better static asset handling to avoid extra function invocations and saving costs (#2822, #2823).
Vercel
When using isr
route rule, by default, query paramas are ignored by cache. Now, you can pass an options object to isr: {}
route rule to configure caching behavior (#2780). Read more in docs.
AWS Lambda
We have experimented streaming support for aws-lambda
(#2412) and added it as an opt-in flag to enable streaming in supported deployments using awsLambda: { streaming: true }
nitro config (#2786).
New presets
We have added support for genezio (#2637) and zerops (#2698) deployment providers.
Other changes
🚀 Enhancements
- Generate types for runtime config (#2306)
- Support
ignore
option for server assets (#2302) - Expose
getRouteRulesForPath
from nitro runtime (#2238) - openapi: Support configuration via
openapi
(#2299) - Environment specific event handlers (#2272)
- Experimental
defineRouteMeta
(#2102) - Allow customizing
apiBaseURL
,apiDir
androutesDir
(#1763) - Add
gitlab-pages
static provider (#2420) - Compatibility date support (#2511)
- config: Warn if the runtime config is not serializable (#2542)
- open-api: Production mode support (#2570)
- deno-server: Use output
node_modules
forstart
task (#2687) - dev-server: Redirect requests without base URL (#2713)
- firebase: Upgrade default runtime to node 20 (#2654)
- Add
.sql
to the default raw file extensions (#2745) - Route groups support (#2664)
- renderer: Add
render:before
hook (#2770) - Add
.pdf
and.wasm
to compressible mime types (#2766) - Include preset config in
.output/nitro.json
(#2807) - Limit open files in
generateFSTree
(#2458) - netlify-legacy: Exclude static paths from server handler (#2823)
- netlify, netlify-edge: Exclude static paths from server handler (#2822)
- cache: Set
ttl
for native expiration (with SWR disabled) (#2783)
🩹 Fixes
- deno-server: Always inject
process
fromnode:process
(#2372) - externals: Compare package paths against normalized
id
(#2371) - azure: Correctly handle
maxAge
cookie option (#2400) - Avoid named exports from
package.json
(e6097ed7) - More compatibility for import from
nitropack/runtime/*
(#2501) - build: Correctly watch custom
apiDir
androutesDir
(#2502) - Make sure nitro runtime goes to one chunk (#2547)
- Backward compatibility types for v2 (#2563)
- handler-meta: Check for
.name
withundefined
value inObjectExpression
(#2565) - Hide unhandled error messages in prod (#2591)
- prerender: Allow ignoring errors in
prerender:generate
hook (#2610) - Only hide messages of unhandled errors in prod (#2619)
- prerender: Skip protocol relative links (#2661)
- Ensure legacy runtime config types are populated (#2724)
- Ensure legacy hook types are populated (#2725)
- Do not generate runtime config types with an external framework (#2732)
- prerender: Log error stack traces (#2720)
- cache: Use top-level
function
to avoid rollup chunk ordering issues (#2741) - cli: Respect custom
buildDir
option fortasks
subcommand (#2635) - Initialize nitro app before plugins run (#1906)
- cloudflare-module: Use correct types for email and queue events/hooks (#2711)
- azure-functions: Follow symlinks in zip bundle (#2769)
- firebase: Validate custom
serverFunctionName
(#2773) - Add
db0
andstd-env
toruntimeDependencies
(a399e189) - error: Add
cache-control: no-cache
for 404 responses (#2793) - renderer: Check
ctx.response
(7a97b0a2) - cf-pages: Only create
wrangler.toml
if the config is not empty (#2356) - netlify: Added missing quotes in utils (#2472)
- netlify: Match ISR route rules when path has a query string (#2440)
- cache: Catch error when getting cache entry (#2609, #2820)
- cache: Try decode path (#2658)
- cloudflare: Support custom
baseURL
(#2821) - Handle incompatible compatibility date for presets (#2828)
💅 Refactors
- cloudflare-pages: Update root
wrangler.toml
in CI (#2355) - Remove dependency on
/runtime/internal/*
subpaths (#2524) - Migrate to
colors
fromconsola/utils
(#2574) - Remove
fs-extra
dependency (#2743) - cache: Remove unnecessary nullish coalescing operator (#2608)
- dev: Attach worker reload error as
cause
(#2651) - Improve type definitions for
CacheOptions
(#2700) - cloudflare-module: Extract reusable logic (#2799)
- firebase: Support
22
fornodeVersion
(#2653)
📦 Build
- Explicitly add
nitropack
to externals for the nightly channel (b2831dd5) - Load presets from unbundled
nitropack/presets
(#2459) - Introduce
nitropack/meta
(ca2282bb) - Improve chunk names (4106750c)
- Mirror
nitro
andnitropack
npm packages (#2497) - Make nightly versions human readable (37f0d4f4)
📖 Documentation
- Correct env variable to
NITRO_SHUTDOWN_DISABLED
(#2377) - Add a usage example for server-sent events (#2379)
- Use
npx nypm install
in instead ofnpm install
(#2421) - node: Fix
node-listener
example (#2456) - Prefix
NITRO_
in.env
file (#2486) - Update h3 docs link to
event-handler
(#2500) - Move
await
to the explicit line for clarity (#2577) - storage: Add
await
beforesetItem
(#2588) - Convert to underscore preset names (#2592)
- cloudflare: Add missing
await
(#2601) - compressPublicAssets: Adjust formatting (#2603)
- routing: Add nested example (#2625)
- Fix component usage and cloudflare preset reference (#2600)
- utils: Update Github link (#2596)
- config: Fix url for log level (#2699)
/_nitro/scalar
general availability (#2754)- Notice for OpenAPI paths changing in future versions (#2755)
- routing: Add error handling section (#2733)
- Update reference to old radix3 link (#2787)
- Fix typos, format and grammar (#2380, #2494, #2578, #2589, #2790, #2805, #2808, #2675, #2728, #2746, #2761, #2669, #2768, #2763, #2368, #2417, #2430, #2594, #2339, #2740, #2386)
🏡 Chore
- Update
@rollup/plugin-commonjs
(eeae2262) - playground: Does not overwrite
tsconfig.paths
(#2507) - Remove unused dependency (#2556)
- Remove extra space in banner (#2573)
- Add
compatibilityDate
to all config files (ced80b21, 2c404995, f70b03c6) - examples: Clarify post handler (#2781)
- examples: Provide
event
indefineEventHandler
function (#2788)
❤️ Contributors
- Pooya Parsa pyapar@gmail.com
- beer (@iiio2)
- Dax d@ironbay.co
- Dawit (@oneminch)
- Alexander a.hywax@gmail.com
- João Carmona
- Aarvin Roshin aarvinr@outlook.com
- Jan-Henrik Damaschke jdamaschke@outlook.de
- Marvin (@marvin-j97)
- Timur tokinoshujin@gmail.com
- Horváth Bálint (@horvbalint)
- Horu
- Balázs Németh (@zsilbi)
- Yoones Khoshghadam yooneskh@gmail.com
- Gautier Ben Aïm (@GauBen)
- Lionel Paulus (@LionelPaulus)
- Gorbasch (@mbegerau)
- Harlan Wilton harlan@harlanzw.com
- Tobias Diez code@tobiasdiez.com
- Connor Pearson (@cjpearson)
- Tim Blommestijn (@TMBL-DEV)
- Daniel Roe (@danielroe)
- Luke Nelson luke@nelson.zone
- Nermal (@nermalcat69)
- Tudor Pipernea (@tudorpip)
- Adam DeHaven (@adamdehaven)
- Gerome Grignon (@geromegrignon)
- Anbraten (@anbraten)
- Philippe Serhal philippe.serhal@netlify.com
- Chris Saganic (@Saganic)
- Juho Rutila (@nice-game-hints)
- Sébastien Chopin (@atinux)
- JinU Choi (@dalbodeule)
- Estéban (@Barbapapazes)
- Maik Kowol maik.s.kowol@gmail.com
- VisuSubbaiyan visu.subbaiyan@gmail.com
- Ashcolor (@ashcolor)
- Guten ywzhaifei@gmail.com
- Matteo Rigoni (@Rigo-m)
- Brandon Roberts (@brandonroberts)
- Ariesly Ariesly.Mao@hotmail.com
- Star Knight (@starknt)
- Jonas Thelemann e-mail@jonas-thelemann.de
- Dominik Rajkowski (@dominiq007)
- Julien Blatecky (@julien1619)
- Ígor Jacaúna (@igorjacauna)
- Leex jsonleex@163.com
- Martins Zeltins
- Markthree (@markthree)
- Matej Černý (@CernyMatej)
- Julien Huang julien.huang@outlook.fr
- Viktor Szépe (@szepeviktor)
- Nicolas Payot nicolas.payot@gmail.com
- BaboonKing changfan.xu.up@qq.com
- Ēriks Lapiņš (@eriksLapins)
- Yuurin (@byyuurin)
- Hans Pagel (@hanspagel)
- Sby1ce (@sby1ce)
- Rahul Mishra blankparticle@gmail.com