Application Hooks

onReady, onClose, onListen — Boot/Shutdown Wiring

Application Hooks

App-level hooks fire during boot and shutdown — perfect homes for database connect/disconnect, warm caches, and graceful shutdown.

4 min read Level 2/5 #fastify#hooks#lifecycle
What you'll learn
  • Use onReady to validate config and warm caches
  • Use onClose to disconnect databases
  • Use onListen for startup logs

While request hooks run per request, application hooks run once per app lifecycle event. They are the right place for setup and teardown.

Boot

app.addHook('onReady', async () => {
  await db.connect();
  await cache.warm();
  app.log.info('app ready');
});

app.addHook('onListen', async () => {
  app.log.info({ url: 'http://localhost:3000' }, 'listening');
});

onReady fires after every plugin has finished registering but before the first request. Throw here to abort startup with a clear log line.

Shutdown

app.addHook('onClose', async () => {
  await db.disconnect();
  await cache.flush();
  app.log.info('app closed');
});

onClose fires when you call app.close(). Pair it with signal handlers for graceful shutdown:

for (const sig of ['SIGINT', 'SIGTERM'] as const) {
  process.on(sig, async () => {
    app.log.info({ sig }, 'shutting down');
    await app.close();
    process.exit(0);
  });
}

Graceful shutdown matters in production. Kubernetes sends SIGTERM and waits up to 30s before SIGKILL — using onClose lets in-flight requests finish and connections drain.

Order of onClose Hooks

Hooks run in reverse registration order, so plugins that depend on the DB are torn down before the DB itself. Encapsulation keeps the order correct without manual choreography.

Decorators — Extend app / request / reply →