Skip to main content
AdonisJS follows a modular architecture built around a powerful IoC (Inversion of Control) container and a well-defined application lifecycle. Understanding these core concepts will help you build robust and maintainable applications.

Core Components

The AdonisJS architecture consists of several key components that work together:

Ignitor

The entry point for bootstrapping your application in different environments

Application

Manages the application lifecycle from initialization to termination

Container

IoC container for dependency injection and service management

Service Providers

Modular units for registering and bootstrapping services

Architecture Flow

The following diagram illustrates how these components interact during application startup:

Application Environments

AdonisJS applications can run in different environments, each optimized for specific use cases:
Used for HTTP server processes. This is the most common environment for production applications.
const ignitor = new Ignitor(new URL('../', import.meta.url))
await ignitor.httpServer().start()
Used for CLI commands and Ace operations. Provides access to the application without starting the HTTP server.
const ignitor = new Ignitor(new URL('../', import.meta.url))
await ignitor.ace().handle(process.argv.slice(2))
Optimized for running tests with utilities for creating test contexts and factories.
const ignitor = new Ignitor(new URL('../', import.meta.url))
await ignitor.testRunner().run(() => {})
Interactive shell environment for exploring your application at runtime.
node ace repl

Dependency Injection

AdonisJS uses constructor-based dependency injection powered by the IoC container:
import { inject } from '@adonisjs/core'
import type { HttpContext } from '@adonisjs/core/http'
import UserService from '#services/user_service'

@inject()
export default class UsersController {
  constructor(protected userService: UserService) {}
  
  async index({ response }: HttpContext) {
    const users = await this.userService.findAll()
    return response.json(users)
  }
}
The @inject() decorator enables automatic dependency resolution from the container. The container will instantiate UserService and inject it into the controller.

Service Registration

Services are registered with the container through service providers. There are three types of bindings:
1

Singleton Bindings

Created once and shared across the application lifetime:
this.app.container.singleton('logger', async () => {
  return new LoggerManager(config)
})
2

Transient Bindings

Created fresh on each resolution:
this.app.container.bind('mailer', async () => {
  return new Mailer(config)
})
3

Value Bindings

Direct value registration:
this.app.container.bindValue('config', configInstance)

Configuration System

AdonisJS uses a type-safe configuration system with support for lazy loading:
import { defineConfig } from '@adonisjs/core/app'

export default defineConfig({
  appKey: env.get('APP_KEY'),
  http: {
    cookie: {},
    trustProxy: false
  }
})
Some configurations support config providers that resolve during the boot phase:
import { defineConfig } from '@adonisjs/lucid'

export default defineConfig({
  type: 'provider',
  resolver: async (app) => {
    return {
      connection: app.env.get('DB_CONNECTION', 'sqlite'),
      connections: {
        // Database connections
      }
    }
  }
})

Next Steps

Ignitor

Learn how the Ignitor bootstraps your application

Application Lifecycle

Understand the application states and lifecycle hooks

Container

Deep dive into the IoC container and dependency injection

Service Providers

Create custom service providers for your modules