0Pricing
NestJS Enterprise Backend APIs · Lesson

Loading Secrets from HashiCorp Vault and AWS SSM

Pull runtime secrets from external stores using async config factories and custom loaders.

Why Pull Secrets at Runtime?

Hardcoding API keys and DB passwords in .env files works for a single laptop, but it falls apart at enterprise scale.

  • Rotation: security teams rotate credentials frequently; baking them into images means a redeploy on every rotation.
  • Auditing: central stores like HashiCorp Vault and AWS SSM Parameter Store log who read which secret and when.
  • Least privilege: each service authenticates with its own identity and only sees the secrets it needs.

In this lesson we wire NestJS's ConfigModule to fetch secrets asynchronously at boot from these external stores using custom loaders.

The Async Config Factory Pattern

NestJS's ConfigModule normally loads from static files. To reach a network store we need code that runs before the rest of the app, returning a plain object of resolved values.

That code is a custom loader — an async function passed to ConfigModule.forRoot({ load: [...] }). Nest awaits each loader and merges the results into the config namespace.

Key rule: a loader must fully resolve its promise before the module finishes initializing, so every downstream provider sees fully-populated config.

// config/config.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { vaultLoader } from './loaders/vault.loader';
import { ssmLoader } from './loaders/ssm.loader';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      // each loader is an async () => Record<string, unknown>
      load: [vaultLoader, ssmLoader],
    }),
  ],
})
export class AppConfigModule {}

All lessons in this course

  1. Schema-Validated Env with Joi and forRoot
  2. Namespaced Config with registerAs
  3. Loading Secrets from HashiCorp Vault and AWS SSM
  4. Per-Environment Config and Safe Defaults
← Back to NestJS Enterprise Backend APIs