Getting Started
Prerequisites
- Node.js >= 22
- pnpm >= 10
- Access to the framework's private registry — see Registry Access for the
.npmrcsetup. Without it,pnpm installcannot resolve@modularityjs/*packages.
Quick start
The fastest way to spin up a new app is the @modularityjs/create scaffolder. It writes the project, wires a working boot script for the contracts you pick, installs dependencies, and initialises git:
pnpm create @modularityjs my-app
cd my-app
pnpm devAdd --yes to skip the prompts and accept the defaults (Fastify + Zod + console logger). See the Create tool docs for every flag.
If you'd rather wire things up by hand, follow the manual installation below.
Installation
Install the framework primitives and a DI driver:
pnpm add @modularityjs/modularity @modularityjs/di @modularityjs/di-inversifyThen add any contract + driver pairs your app needs. For a minimal HTTP server:
pnpm add @modularityjs/http @modularityjs/http-fastifyFor CLI support:
pnpm add @modularityjs/cli @modularityjs/cli-commanderCreating Your First App
Every ModularityJS application starts with createApp(). You pass it a DI driver and a list of modules:
import { ModularityModule, createApp } from '@modularityjs/modularity';
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:
import { Inject, Injectable } from '@modularityjs/di';
import { Module } from '@modularityjs/modularity';
@Injectable()
class GreeterService {
greet(name: string): string {
return `Hello, ${name}!`;
}
}
@Module({
name: 'greeter',
providers: [GreeterService],
})
class GreeterModule {}Register the module with createApp():
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:
import { CacheModule } from '@modularityjs/cache';
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:
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:
- Boot (
createApp()) — loads modules, resolves DI, validates contracts, runsafterLoadthenonInithooks - Start (
app.start()) — runsonReadyhooks (starts HTTP servers, schedulers, etc.)
Shutdown is handled automatically via signal handlers, or manually:
await app.shutdown(); // runs onShutdown, then onDestroyNext 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