Bootstrap Helpers
Overview
The @nx/core package provides three bootstrap utilities that standardize how every BANA service starts and how database migrations run. These helpers encapsulate the IGNIS application lifecycle, handle errors uniformly, and ensure every package follows the same initialization sequence.
| Helper | Purpose | Source |
|---|---|---|
bootstrapApplication | Start an HTTP service | src/helpers/bootstraps/application.ts |
bootstrapMigration | Run database seed/migration processes | src/helpers/bootstraps/migration.ts |
createMigrationProcessLoader | Dynamically import migration process files | src/helpers/migration/process-loader.ts |
MigrationHelper | Execute cleanup and migrate phases with status tracking | src/helpers/migration/helper.ts |
bootstrapApplication
Creates, initializes, boots, and starts an IGNIS application. On success it optionally prints an ASCII banner. On failure it logs the error and exits the process with code 1.
Signature
bootstrapApplication(opts: {
ApplicationClass: new (opts: {
scope: string;
config: IApplicationConfigs;
}) => DefaultApplication;
config: IApplicationConfigs;
options?: { bannerPath?: string };
}): Promise<void>Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ApplicationClass | Constructor of DefaultApplication | Yes | The application class to instantiate |
config | IApplicationConfigs | Yes | Server host, port, base path, boot options |
options.bannerPath | string | No | Absolute path to an ASCII banner file printed after successful start |
Lifecycle Sequence
Usage
Every package entry point (src/index.ts) follows the same pattern:
// packages/sale/src/index.ts
import { bootstrapApplication } from '@nx/core';
import { resolve } from 'node:path';
import { appConfig, Application } from './application';
bootstrapApplication({
ApplicationClass: Application,
config: appConfig,
options: { bannerPath: resolve(process.cwd(), 'resources/banner.txt') },
});bootstrapMigration
Creates a minimal application instance sufficient to connect to the database, registers the MigrationRepository, and runs all migration processes via MigrationHelper.
Signature
bootstrapMigration(opts: {
ApplicationClass: new (opts: {
scope: string;
config: IApplicationConfigs;
}) => DefaultApplication;
getMigrationProcesses: () => Promise<TMigrationProcess[]>;
}): Promise<void>Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ApplicationClass | Constructor of DefaultApplication | Yes | The application class (same as used for serving) |
getMigrationProcesses | () => Promise<TMigrationProcess[]> | Yes | A function returning an array of migration process definitions |
Lifecycle Sequence
Usage
Every package migration entry point (src/migrate.ts) follows this pattern:
// packages/sale/src/migrate.ts
import { bootstrapMigration } from '@nx/core';
import { Application } from './application';
import { getMigrationProcesses } from './migrations/processes/migration-process';
bootstrapMigration({
ApplicationClass: Application,
getMigrationProcesses,
})
.then(() => {
process.exit(0);
})
.catch(err => {
console.error('Cannot migrate database schema', err);
process.exit(1);
});createMigrationProcessLoader
A factory function that returns an async function for dynamically importing migration process files. Each file must export a TMigrationProcess as its default export. Files that fail to import or lack a default export are silently skipped.
Signature
createMigrationProcessLoader(opts: {
seedPaths: string[];
importFn: (path: string) => Promise<any>;
}): () => Promise<TMigrationProcess[]>Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
seedPaths | string[] | Yes | Ordered list of migration file names (without extension) |
importFn | (path: string) => Promise<any> | Yes | Dynamic import function that resolves file paths |
Usage
// packages/payment/src/migrations/processes/migration-process.ts
import { createMigrationProcessLoader } from '@nx/core';
export const getMigrationProcesses = createMigrationProcessLoader({
seedPaths: [
'payment-0001-seed-vnpay-qr-mms-configuration',
'payment-0002-seed-vnpay-phone-pos-configuration',
],
importFn: path => import(`../processes/${path}.js`),
});Packages without seed data pass an empty array:
// packages/sale/src/migrations/processes/migration-process.ts
import { createMigrationProcessLoader } from '@nx/core';
export const getMigrationProcesses = createMigrationProcessLoader({
seedPaths: [],
importFn: path => import(`../processes/${path}.js`),
});TMigrationProcess
The type definition for a single migration process.
Type Definition
type TMigrationProcess<
ExtraOptionsType extends { alwaysRun?: boolean } = { alwaysRun?: boolean },
> = {
name: string;
cleanFn?: (opts: { context: BaseApplication }) => ValueOrPromise<void>;
migrateFn: (opts: { context: BaseApplication }) => ValueOrPromise<void>;
options?: ExtraOptionsType;
};Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique migration identifier, stored in the Migration table |
cleanFn | (opts) => void | No | Cleanup function called before migration (e.g., drop old data) |
migrateFn | (opts) => void | Yes | The migration logic (seed data, schema changes, etc.) |
options.alwaysRun | boolean | No | When true, re-runs even if previously recorded as SUCCESS |
Writing a Migration Process
// packages/payment/src/migrations/processes/payment-0001-seed-vnpay-qr-mms-configuration.ts
import { TMigrationProcess } from '@nx/core';
const process: TMigrationProcess = {
name: 'payment-0001-seed-vnpay-qr-mms-configuration',
migrateFn: async ({ context }) => {
const repository = context.get({ key: 'repositories.ConfigurationRepository' });
await repository.create({
data: {
key: 'VNPAY_QR_MMS',
value: JSON.stringify({ /* provider config */ }),
},
});
},
};
export default process;MigrationHelper
Orchestrates the full migration workflow: cleanup followed by migration. It tracks each migration's status (SUCCESS or FAIL) in the Migration database table and supports lifecycle hooks.
Workflow
Migration Hooks
Hooks allow external code to observe or extend the migration lifecycle:
type TMigrationHooks = {
beforeCleanup?: (opts: { context: BaseApplication; processes: TMigrationProcess[] }) => void;
afterCleanup?: (opts: { context: BaseApplication; processes: TMigrationProcess[] }) => void;
beforeMigration?: (opts: { context: BaseApplication; processes: TMigrationProcess[] }) => void;
afterMigration?: (opts: { context: BaseApplication; processes: TMigrationProcess[] }) => void;
onMigrationSuccess?: (opts: { name: string; process: TMigrationProcess; duration: number }) => void;
onMigrationError?: (opts: { name: string; process: TMigrationProcess; error: unknown }) => void;
};| Hook | When | Receives |
|---|---|---|
beforeCleanup | Before the cleanup phase begins | Application context, all processes |
afterCleanup | After all cleanup functions complete | Application context, all processes |
beforeMigration | Before the migration phase begins | Application context, all processes |
afterMigration | After all migration functions complete | Application context, all processes |
onMigrationSuccess | After a single process succeeds | Process name, process definition, duration (ms) |
onMigrationError | After a single process fails | Process name, process definition, error |
All hooks are wrapped in try/catch internally. A failing hook logs a warning but does not halt the migration.
Status Tracking
The MigrationHelper uses the MigrationRepository (registered automatically by bootstrapMigration) to persist each process's result:
| Status | Meaning |
|---|---|
SUCCESS | Migration completed without errors |
FAIL | Migration threw an error |
UNKNOWN | Initial state before execution |
On subsequent runs, processes with status SUCCESS are skipped unless options.alwaysRun is set to true.
Package Adoption
Every backend package in BANA uses these helpers. The table below shows the pattern across all packages:
| Package | index.ts | migrate.ts | Seed Paths |
|---|---|---|---|
@nx/sale | bootstrapApplication | bootstrapMigration | [] |
@nx/identity | bootstrapApplication | bootstrapMigration | (identity seeds) |
@nx/commerce | bootstrapApplication | bootstrapMigration | (commerce seeds) |
@nx/inventory | bootstrapApplication | bootstrapMigration | (inventory seeds) |
@nx/finance | bootstrapApplication | bootstrapMigration | (finance seeds) |
@nx/payment | bootstrapApplication | bootstrapMigration | payment-0001-*, payment-0002-* |
@nx/signal | bootstrapApplication | N/A (stateless) | N/A |
Related Resources
- IGNIS Bootstrapping Reference -- Application lifecycle interfaces and boot options
- IGNIS Application Concepts -- Creating and configuring applications
- DefaultApplication -- The base class used by
ApplicationClass - Database Migrations -- Migration schema and table details