Plugins
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. |
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. |
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");
}
});
});