Skip to content

The Application Class

The Application class orchestrates your application's configuration, lifecycle, and resource registration (components, controllers, services).

Deep Dive: See Application Reference for technical details.

Creating an Application

Extend BaseApplication and implement the hook methods:

typescript
// src/application.ts
import {
  BaseApplication,
  IApplicationConfigs,
  IApplicationInfo,
  ValueOrPromise,
} from "@venizia/ignis";
import packageJson from "./../package.json";

// Application configurations
export const appConfigs: IApplicationConfigs = {
  host: process.env.APP_ENV_SERVER_HOST,
  port: +(process.env.APP_ENV_SERVER_PORT ?? 3000),
  path: {
    base: process.env.APP_ENV_SERVER_BASE_PATH,
    isStrict: true,
  },
  debug: {
    showRoutes: process.env.NODE_ENV !== "production",
  },
};

// Main Application class
export class Application extends BaseApplication {
  override getAppInfo(): ValueOrPromise<IApplicationInfo> {
    return packageJson;
  }

  staticConfigure(): void {
    // e.g., this.static({ folderPath: './public' })
  }
  
  preConfigure(): ValueOrPromise<void> {
    // Manual registration (traditional approach)
    this.dataSource(MyDataSource);
    this.service(MyService);
    this.controller(MyController);
    
    // Or use boot system for auto-discovery (recommended for larger apps)
    // See Bootstrapping section below
  }
  
  postConfigure(): ValueOrPromise<void> {
    // Logic to run after everything is configured
  }
  
  setupMiddlewares(): ValueOrPromise<void> {
    // Add any custom application-wide middlewares
  }
}

Application Lifecycle

The Ignis application has a well-defined lifecycle, managed primarily by the start() and initialize() methods.

MethodDescription
constructor(opts)Initializes the application, sets up the Hono server, and detects the runtime (Bun/Node).
start()The main entry point. It calls initialize(), sets up middlewares, and starts the HTTP server.
stop()Stops the application server.
initialize()Orchestrates the entire setup process, calling the various configuration and registration methods in the correct order.

The BaseApplication class provides several overridable hook methods that allow you to customize the startup process. These are the primary places you'll write your application-specific setup code.

Hook MethodPurpose
getAppInfo()Required. Return application metadata, usually from package.json. Used for OpenAPI docs.
staticConfigure()Configure static file serving.
preConfigure()Most Important Hook. Set up application resources like components, controllers, services, and datasources. Can be skipped if using boot system.
postConfigure()Perform actions after all resources have been configured and instantiated.
setupMiddlewares()Add custom application-level middlewares to the Hono instance.

Bootstrapping (Auto-discovery)

The boot system provides automatic artifact discovery and loading, eliminating manual registration. When enabled, it scans your project directory and automatically loads controllers, services, repositories, and datasources.

Detailed Guide: See Bootstrapping Concepts for complete documentation.

Enabling Boot System

Add bootOptions to your application config:

typescript
export const appConfigs: IApplicationConfigs = {
  host: process.env.APP_ENV_SERVER_HOST,
  port: +(process.env.APP_ENV_SERVER_PORT ?? 3000),
  // Enable boot system
  bootOptions: {
    datasources: { dirs: ['datasources'] },
    repositories: { dirs: ['repositories'] },
    services: { dirs: ['services'] },
    controllers: { dirs: ['controllers'] }
  }
};

With boot enabled, you can skip manual registration in preConfigure():

typescript
export class Application extends BaseApplication {
  // No need to register artifacts manually!
  // Boot system handles it automatically
  
  preConfigure(): ValueOrPromise<void> {
    // Only register things that need custom configuration
    // Everything else is auto-discovered
  }
}

Boot vs Manual Registration

ApproachUse CaseProsCons
Boot SystemApps with 10+ artifacts per typeAuto-discovery, scalable, clean codeRequires file naming conventions
Manual RegistrationSmall apps (< 5 artifacts)Fine-grained control, explicitTedious, maintenance burden

Project Structure for Boot

Follow naming conventions for auto-discovery:

src/
├── datasources/
│   └── postgres.datasource.js
├── repositories/
│   ├── user.repository.js
│   └── product.repository.js
├── services/
│   ├── auth.service.js
│   └── user.service.js
└── controllers/
    ├── auth.controller.js
    └── user.controller.js

Lifecycle Diagram

This diagram shows the sequence of operations during application startup. The methods you can override are highlighted.

Configuration

Application configuration is passed to the BaseApplication constructor via an IApplicationConfigs object.

Configuration Options

OptionTypeDefaultDescription
hoststring'localhost'The host address to bind the server to.
portnumber3000The port to listen on.
path.basestring'/'The base path for all application routes (e.g., /api).
path.isStrictbooleantrueIf true, the router is strict about trailing slashes.
debug.showRoutesbooleanfalseIf true, prints all registered routes to the console on startup.
faviconstring'🔥'An emoji to be used as the application's favicon.
bootOptionsIBootOptionsundefinedEnable auto-discovery of artifacts. See Bootstrapping.

Example Configuration

typescript
export const appConfigs: IApplicationConfigs = {
  host: "0.0.0.0",
  port: 3000,
  path: {
    base: "/api",
    isStrict: true,
  },
  debug: {
    showRoutes: true,
  },
};

Registering Resources

Register resources in preConfigure() to tell the DI container about your classes:

MethodExampleWhen to Use
this.controller(...)this.controller(UserController)Register API endpoints
this.service(...)this.service(UserService)Register business logic
this.repository(...)this.repository(UserRepository)Register data access
this.dataSource(...)this.dataSource(PostgresDataSource)Register database connection
this.component(...)this.component(AuthComponent)Register reusable modules

Registration order:

  1. DataSources first (database connections)
  2. Repositories (depend on DataSources)
  3. Services (depend on Repositories)
  4. Controllers (depend on Services)
  5. Components last

Deep Dive: See Dependency Injection for how registration and injection work together.