Skip to content

Getting Started

Prerequisites

  • Node.js >= 22
  • pnpm

Installation

bash
pnpm add @modularityjs/core @modularityjs/di-inversify

For CLI support:

bash
pnpm add @modularityjs/core-cli

Creating Your First App

Every ModularityJS application starts with createApp(). You pass it a DI driver and a list of modules:

typescript
import { createApp, ModularityModule } from '@modularityjs/core';
import { inversify } from '@modularityjs/di-inversify';

const app = await createApp({
  di: inversify,
  modules: [ModularityModule],
});

await app.start();

Adding a Module

Modules are classes decorated with @Module(). They declare providers, imports, and configuration:

typescript
import { Injectable, Inject, Module } from '@modularityjs/core';

@Injectable()
class GreeterService {
  greet(name: string): string {
    return `Hello, ${name}!`;
  }
}

@Module({
  name: 'greeter',
  providers: [GreeterService],
})
class GreeterModule {}

Register the module with createApp():

typescript
const app = await createApp({
  di: inversify,
  modules: [ModularityModule, GreeterModule],
});

const greeter = app.get(GreeterService);
console.log(greeter.greet('World')); // Hello, World!

Adding Drivers

Drivers implement abstract service contracts. For example, to add caching:

typescript
import { CacheModule } from '@modularityjs/core';
import { CacheMemoryModule } from '@modularityjs/cache-memory';

const app = await createApp({
  di: inversify,
  modules: [
    ModularityModule,
    CacheModule,
    CacheMemoryModule, // in-memory for development
    GreeterModule,
  ],
});

To switch to Redis in production, replace the driver:

typescript
import { CacheRedisModule } from '@modularityjs/cache-redis';
import { RedisModule } from '@modularityjs/redis';

const app = await createApp({
  di: inversify,
  modules: [
    ModularityModule,
    RedisModule.forRoot({ host: 'redis.prod.internal' }),
    CacheModule,
    CacheRedisModule, // Redis for production
    GreeterModule,
  ],
});

No changes to your application code. The CacheService contract is the same — only the driver changed.

Lifecycle

Applications have a two-phase lifecycle:

  1. Boot (createApp()) — loads modules, resolves DI, validates contracts, runs onInit hooks
  2. Start (app.start()) — runs onReady hooks (starts HTTP servers, schedulers, etc.)

Shutdown is handled automatically via signal handlers, or manually:

typescript
await app.shutdown(); // runs onShutdown, then onDestroy

Next Steps

  • Architecture — understand how the module system works
  • Modules — deep dive into @Module, lifecycle hooks, and pools
  • Configuration — config sources, schemas, and validation
  • Packages — available contracts and drivers