Plugins
Use runtime plugins to extend Nitro's runtime behavior.
Runtime plugins are executed once during server startup, making them the right place for one-time initialization and for registering lifecycle hooks. Each plugin receives the nitroApp context.
Plugins are auto-registered from the plugins/ directory and run synchronously in file name order. Plugin functions themselves must be synchronous (return void), but the hooks they register can be async.
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
console.log('Nitro plugin', nitroApp)
})If you have plugins in another directory, you can use the plugins option:
import { defineConfig } from "nitro";
export default defineConfig({
plugins: ['my-plugins/hello.ts']
})#The nitroApp context
The plugin function receives a nitroApp object with the following properties:
| Property | Type | Description |
|---|---|---|
hooks | HookableCore | Hook system for registering lifecycle callbacks. |
h3 | H3Core | The underlying H3 application instance. |
fetch | (req: Request) => Response | Promise<Response> | The app's internal fetch handler. |
captureError | (error: Error, context) => void | Programmatically capture errors into the error hook pipeline. |
Note
H3 composes the middleware chain once, on the first request. Middleware a plugin adds to nitroApp.h3["~middleware"] during startup is included, but it runs before Nitro's route rules when placed at the front of the array. If a plugin changes the array after the first request was handled, it must also reset nitroApp.h3["~dispatch"] and nitroApp.h3["~composed"] to undefined so the chain is recomposed.
#Nitro runtime hooks
Use Nitro hooks to run custom functions at specific points in the request lifecycle. Register them inside plugins with nitroApp.hooks.hook():
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.hooks.hook("close", async () => {
// Will run when nitro is being closed
});
})#Available hooks
| Hook | Signature | Description |
|---|---|---|
request | (event: HTTPEvent) => void | Promise<void> | Called at the start of each request. |
response | (res: Response, event: HTTPEvent) => void | Promise<void> | Called after the response is created. |
error | (error: Error, context: { event?: HTTPEvent, tags?: string[] }) => void | Called when an error is captured. |
close | () => void | Called when the Nitro server is shutting down. |
Note
The NitroRuntimeHooks interface is augmentable. Deployment presets (such as Cloudflare) can extend it with platform-specific hooks like cloudflare:scheduled and cloudflare:email.
#Unregistering hooks
The hook() method returns an unregister function that can be called to remove the hook:
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
const unregister = nitroApp.hooks.hook("request", (event) => {
// ...
});
// Later, remove the hook
unregister();
});#Examples
#Capturing errors
You can use plugins to capture all application errors.
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.hooks.hook("error", async (error, { event }) => {
console.error(`${event?.req.url} Application error:`, error)
});
})The context object includes an optional tags array that identifies the error source (e.g., "request", "response", "cache", "plugin", "unhandledRejection", "uncaughtException").
#Programmatic error capture
You can use captureError to manually feed errors into the error hook pipeline:
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.captureError(new Error("something went wrong"), {
tags: ["startup"],
});
});#Graceful shutdown
The server shuts down gracefully, waiting for any pending background tasks started with event.waitUntil. Use the close hook to clean up your own resources:
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.hooks.hook("close", async () => {
// Clean up resources, close connections, etc.
});
});#Request and response lifecycle
You can use plugins to register hooks that run on the request lifecycle:
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.hooks.hook("request", (event) => {
console.log("on request", event.req.url);
});
nitroApp.hooks.hook("response", (res, event) => {
// Modify or inspect the response
console.log("on response", res.status);
});
});#Modifying response headers
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.hooks.hook("response", (res, event) => {
const { pathname } = new URL(event.req.url);
if (pathname.endsWith(".css") || pathname.endsWith(".js")) {
res.headers.append("Vary", "Origin");
}
});
});