Skip to content

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.

HelperPurposeSource
bootstrapApplicationStart an HTTP servicesrc/helpers/bootstraps/application.ts
bootstrapMigrationRun database seed/migration processessrc/helpers/bootstraps/migration.ts
createMigrationProcessLoaderDynamically import migration process filessrc/helpers/migration/process-loader.ts
MigrationHelperExecute cleanup and migrate phases with status trackingsrc/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

typescript
bootstrapApplication(opts: {
  ApplicationClass: new (opts: {
    scope: string;
    config: IApplicationConfigs;
  }) => DefaultApplication;
  config: IApplicationConfigs;
  options?: { bannerPath?: string };
}): Promise<void>

Parameters

ParameterTypeRequiredDescription
ApplicationClassConstructor of DefaultApplicationYesThe application class to instantiate
configIApplicationConfigsYesServer host, port, base path, boot options
options.bannerPathstringNoAbsolute path to an ASCII banner file printed after successful start

Lifecycle Sequence

Usage

Every package entry point (src/index.ts) follows the same pattern:

typescript
// 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

typescript
bootstrapMigration(opts: {
  ApplicationClass: new (opts: {
    scope: string;
    config: IApplicationConfigs;
  }) => DefaultApplication;
  getMigrationProcesses: () => Promise<TMigrationProcess[]>;
}): Promise<void>

Parameters

ParameterTypeRequiredDescription
ApplicationClassConstructor of DefaultApplicationYesThe application class (same as used for serving)
getMigrationProcesses() => Promise<TMigrationProcess[]>YesA function returning an array of migration process definitions

Lifecycle Sequence

Usage

Every package migration entry point (src/migrate.ts) follows this pattern:

typescript
// 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

typescript
createMigrationProcessLoader(opts: {
  seedPaths: string[];
  importFn: (path: string) => Promise<any>;
}): () => Promise<TMigrationProcess[]>

Parameters

ParameterTypeRequiredDescription
seedPathsstring[]YesOrdered list of migration file names (without extension)
importFn(path: string) => Promise<any>YesDynamic import function that resolves file paths

Usage

typescript
// 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:

typescript
// 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

typescript
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

FieldTypeRequiredDescription
namestringYesUnique migration identifier, stored in the Migration table
cleanFn(opts) => voidNoCleanup function called before migration (e.g., drop old data)
migrateFn(opts) => voidYesThe migration logic (seed data, schema changes, etc.)
options.alwaysRunbooleanNoWhen true, re-runs even if previously recorded as SUCCESS

Writing a Migration Process

typescript
// 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:

typescript
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;
};
HookWhenReceives
beforeCleanupBefore the cleanup phase beginsApplication context, all processes
afterCleanupAfter all cleanup functions completeApplication context, all processes
beforeMigrationBefore the migration phase beginsApplication context, all processes
afterMigrationAfter all migration functions completeApplication context, all processes
onMigrationSuccessAfter a single process succeedsProcess name, process definition, duration (ms)
onMigrationErrorAfter a single process failsProcess 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:

StatusMeaning
SUCCESSMigration completed without errors
FAILMigration threw an error
UNKNOWNInitial 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:

Packageindex.tsmigrate.tsSeed Paths
@nx/salebootstrapApplicationbootstrapMigration[]
@nx/identitybootstrapApplicationbootstrapMigration(identity seeds)
@nx/commercebootstrapApplicationbootstrapMigration(commerce seeds)
@nx/inventorybootstrapApplicationbootstrapMigration(inventory seeds)
@nx/financebootstrapApplicationbootstrapMigration(finance seeds)
@nx/paymentbootstrapApplicationbootstrapMigrationpayment-0001-*, payment-0002-*
@nx/signalbootstrapApplicationN/A (stateless)N/A

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.