nnestjs-drizzle-crud
Configuration

forRootAsync

Configure the database connection asynchronously, e.g. from ConfigService.

DrizzleCrudModule.forRootAsync(options) is the asynchronous variant of forRoot. Use it when your configuration is built at runtime — typically read from ConfigService after env validation.

Signature

DrizzleCrudModule.forRootAsync({
  imports?: ModuleClass[];
  useFactory: (...deps: any[]) => Promise<DrizzleCrudConfig> | DrizzleCrudConfig;
  inject?: any[];
}): DynamicModule

Example — with @nestjs/config

app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { DrizzleCrudModule } from 'nestjs-drizzle-crud';
import { schema } from './db/schema';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    DrizzleCrudModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (cfg: ConfigService) => ({
        dialect: 'postgresql',
        connectionString: cfg.getOrThrow<string>('DATABASE_URL'),
        schema,
        defaults: {
          pagination: { defaultLimit: 20, maxLimit: 100 },
        },
      }),
    }),
  ],
})
export class AppModule {}

The useFactory may return a Promise<DrizzleCrudConfig> if you need to read from a remote source (Vault, AWS SSM, etc.) before constructing the config object.

Example — pre-built Drizzle instance with config

app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import { DrizzleCrudModule } from 'nestjs-drizzle-crud';
import { schema } from './db/schema';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    DrizzleCrudModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (cfg: ConfigService) => {
        const client = postgres(cfg.getOrThrow<string>('DATABASE_URL'));
        return {
          dialect: 'postgresql',
          db: drizzle(client, { schema }),
        };
      },
    }),
  ],
})
export class AppModule {}

Example — multiple injected services

DrizzleCrudModule.forRootAsync({
  imports: [ConfigModule, FeatureFlagsModule],
  inject: [ConfigService, FeatureFlagsService],
  useFactory: (cfg: ConfigService, flags: FeatureFlagsService) => ({
    dialect: 'postgresql',
    connectionString: cfg.getOrThrow('DATABASE_URL'),
    schema,
    sql: {
      enableFullTextSearch: flags.isEnabled('fts'),
    },
  }),
})

useClass / useExisting

forRootAsync exposes useFactory directly — it does not accept useClass or useExisting. If you need a class-based config, wrap it:

class CrudConfigService {
  constructor(private readonly cfg: ConfigService) {}
  create() {
    return { dialect: 'postgresql' as const, /* ... */ };
  }
}

DrizzleCrudModule.forRootAsync({
  imports: [ConfigModule],
  inject: [CrudConfigService, ConfigService],
  useFactory: (svc: CrudConfigService) => svc.create(),
})

When to use forRoot vs forRootAsync

Use forRoot when the config object can be built statically at module-evaluation time. Use forRootAsync when any of:

  • The connection string is read from process.env and you want validation via ConfigService.
  • The Drizzle instance is built from config (e.g. dynamic pool size).
  • You depend on another provider in useFactory (feature flags, secrets manager).

Next

On this page