Skip to main content

Lifecycle Hooks

TSDIAPI provides several lifecycle hooks that allow you to execute code at specific points during your application's lifecycle.

Available Hooks

onInit

Called when the application is initialized, before any other hooks. This is the ideal place for:

  • Setting up initial configurations
  • Registering services
  • Initializing external connections
createApp<ConfigType>({
onInit: async (ctx) => {
// Access configuration
const port = ctx.projectConfig.get('PORT', 3000);
const host = ctx.projectConfig.get('HOST', 'localhost');

// Initialize services
await initializeServices();

console.log('Application initialized');
}
});

beforeStart

Executed before the server starts listening for requests. Use this hook for:

  • Final configuration checks
  • Database migrations
  • Resource validation
createApp<ConfigType>({
beforeStart: async (ctx) => {
// Verify database connection
await checkDatabaseConnection();

// Run migrations
await runMigrations();

console.log('Pre-start checks completed');
}
});

preReady

Runs before the server is marked as ready. Perfect for:

  • Loading initial data
  • Warming up caches
  • Setting up background tasks
createApp<ConfigType>({
preReady: async (ctx) => {
// Load cache
await warmupCache();

// Initialize background workers
await startBackgroundWorkers();

console.log('Server preparing to be ready');
}
});

afterStart

Triggered after the server has started and is ready to accept requests. Use this for:

  • Starting background jobs
  • Logging server status
  • Sending notifications
createApp<ConfigType>({
afterStart: async (ctx) => {
const address = ctx.fastify.server.address();
console.log(`Server started on ${address}`);

// Start scheduled tasks
startScheduledJobs();
}
});

Using Hooks in Plugins

Plugins can also implement lifecycle hooks. This allows you to modularize your application's initialization logic:

const MyPlugin: AppPlugin = {
name: 'my-plugin',

onInit: async (ctx) => {
// Plugin initialization
console.log('Initializing my plugin');
},

beforeStart: async (ctx) => {
// Pre-start setup
await setupPluginResources();
},

preReady: async (ctx) => {
// Prepare plugin
await warmupPluginCache();
},

afterStart: async (ctx) => {
// Plugin is ready
console.log('Plugin started successfully');
}
};

Hook Context

All hooks receive an AppContext object that provides access to:

interface AppContext<T> {
// Fastify instance
fastify: FastifyInstance;

// Current environment
environment: 'production' | 'development';

// Application directory
appDir: string;

// Application options
options: AppOptions<T>;

// File handling
fileLoader?: FileLoader;

// Configuration
projectConfig: AppConfig<T>;

// Package.json contents
projectPackage: Record<string, any>;

// Loaded plugins
plugins?: Record<string, AppPlugin>;

// Route builder
useRoute: RouteBuilder;
}

Best Practices

  1. Asynchronous Operations
    • All hooks support async/await
    • Handle errors properly in async operations
    • Use try/catch blocks for critical operations
createApp<ConfigType>({
onInit: async (ctx) => {
try {
await initializeCriticalServices();
} catch (error) {
console.error('Failed to initialize:', error);
process.exit(1);
}
}
});
  1. Order of Operations

    • Use appropriate hooks for different tasks
    • Don't perform heavy operations in afterStart
    • Keep initialization logic in onInit
  2. Error Handling

    • Handle errors appropriately in each hook
    • Log errors with proper context
    • Consider the impact of hook failures
createApp<ConfigType>({
beforeStart: async (ctx) => {
try {
await validateResources();
} catch (error) {
ctx.fastify.log.error('Resource validation failed:', error);
throw error; // Stop server startup if critical
}
}
});
  1. Configuration Access
    • Use projectConfig for accessing configuration
    • Validate configuration values early
    • Set appropriate defaults
createApp<ConfigType>({
onInit: async (ctx) => {
const dbUrl = ctx.projectConfig.get('DATABASE_URL');
if (!dbUrl) {
throw new Error('DATABASE_URL is required');
}
}
});

Hook Execution Order

  1. onInit - Application initialization
  2. beforeStart - Pre-server start checks
  3. preReady - Final preparations
  4. afterStart - Post-server start tasks

Each hook must complete successfully before the next one is executed. If any hook throws an error, the application startup will fail.