🔌 NestJS-TypeORM-AWS-Connector
Seamlessly bridge TypeORM with AWS Parameter Store & Secrets Manager for secure, auto-rotating database connections in NestJS
💡 Highlights
- 🔐 Zero-credential codebase — resolves all database config from AWS SSM Parameter Store & Secrets Manager at runtime
- ♻️ Bounded automatic credential rotation with health checks, transaction affinity, and at most one retiring pool
- ⏱️ Bounded shutdown with explicit drain timeout, aggregate failure, and package-neutral lifecycle events
- 🏗️ Split-source architecture — infra teams own host/port/secrets, app teams own pool/timeout/sync settings independently
- 📦 ES module build with extension-qualified TypeScript declarations for NestJS 12 and TypeORM 1, loadable from CommonJS through
require(esm)
📚 Table of Contents
- Description
- Tech Stack
- Features
- Architecture
- Project Structure
- Prerequisites
- Installation
- Usage
- Migrating to 3.0
- Migrating to 2.0
- Roadmap
- FAQ
- License
- Acknowledgments
📖 Description
NestJS-TypeORM-AWS-Connector is a production-grade NestJS module that eliminates the pain of managing database configuration in AWS-hosted applications. Instead of hardcoding credentials or juggling environment variables, this connector resolves your entire TypeORM DataSourceOptions from AWS Systems Manager Parameter Store and AWS Secrets Manager — with built-in credential rotation.
In modern cloud-native architectures, database credentials are rotated regularly for security compliance. Traditional approaches break connections during rotation, causing downtime. This connector avoids destructive mid-run DataSource teardown by validating a replacement connection first, promoting the new driver for future query runners, and retiring the previous pool only after existing query runners drain. It permits at most one current and one retiring generation; later intervals defer instead of growing the pool count.
Real-World Use Cases
- ECS Fargate Microservices: Deploy NestJS APIs on Fargate where credentials are managed by AWS Secrets Manager with automatic rotation policies — the connector picks up fresh credentials without redeployment.
- Multi-Environment Deployments: Use the same codebase across
dev,staging, andproduction— each environment resolves its own database configuration from namespaced SSM parameters. - Aurora PostgreSQL / RDS MySQL: Connect to managed AWS databases where infrastructure teams control host, port, and secret references via Parameter Store, while application teams only configure entities and behavior.
- Compliance-First Organizations: Meet SOC2 and PCI-DSS requirements by never storing credentials in code, environment files, or container images.
The connector uses a split-source model: infrastructure-owned parameters (host, port, secret ID) live in canonical AWS namespaces, while application-owned settings (pool size, timeouts, sync behavior) live in your app's namespace. Raw value overrides let you bypass SSM entirely for local development.
🛠️ Tech Stack
| Category | Technologies |
|---|---|
| Language | TypeScript |
| Runtime | Node.js |
| Framework | NestJS |
| ORM | TypeORM |
| Cloud Services | AWS SSM Parameter Store, AWS Secrets Manager |
| Build Tool | Rollup |
| Linting | ESLint, Prettier |
| CI/CD | GitHub Actions, Semantic Release |
| Package Manager | npm |
🚀 Features
- ✨ AWS Parameter Store Integration — Resolves database host, port, name, type, and tuning parameters from structured SSM paths with hierarchical namespace support
- ✨ AWS Secrets Manager Integration — Fetches username/password credentials from Secrets Manager with proper error handling for missing or malformed secrets
- ✨ Bounded Credential Rotation — Validates a replacement before promotion and permits only the current pool plus one retiring pool
- ✨ Transaction Affinity — Query runners and manager-bound transactions stay on the generation where they started
- ✨ Bounded Shutdown — Stops new work, waits for active generations, then reports timeout or close failures as one aggregate error
- ✨ Rotation Events — Reports deferred rotation, retired generations, and drain timeouts without a Nest EventEmitter dependency
- ✨ Emergency Recovery — After 3 consecutive rotation failures, automatically retries recovery without destructively tearing down the live
DataSource - ✨ Connection Health Validation — Validates both existing and new connections with
SELECT 1queries before and after rotation - ✨ Split-Source Configuration Model — Infrastructure-owned settings (host, port, secret-id) use canonical AWS namespaces; app-owned settings use your module namespace
- ✨ Raw Value Overrides — Bypass SSM entirely for any field by providing direct values — perfect for local development with
host: '127.0.0.1' - ✨ Hierarchical Lookup Resolution — Field-level SSM lookup → canonical defaults → ssmLookupDefaults → ParameterStoreConfigModule defaults
- ✨ ES Module Build — Ships ES modules with extension-qualified TypeScript declarations and source maps; CommonJS applications load it through
require(esm) - ✨ Bounded Error Model — Static diagnostics expose only a validated error type and optional SQLSTATE while retaining the original failure as
cause - ✨ NestJS 12 and TypeORM 1 — Peers
@nestjs/commonand@nestjs/core>=12.3.2 <13andtypeorm>=1.1.2 <2 - ✨ Sync & Async Registration — Use
register()for static config orregisterAsync()with factory functions for dynamic configuration
🏗 Architecture
System Architecture
flowchart TD
appModule[AppModule] --> paramStore[ParameterStoreConfigModule]
appModule --> connectorModule[TypeOrmAwsConnectorModule]
connectorModule --> connectorService[TypeOrmAwsConnectorService]
connectorModule --> rotatorService[RotatorService]
connectorModule --> scheduleModule[ScheduleModule]
connectorService --> paramStoreService[ParameterStoreConfigService]
connectorService --> configService[NestJS ConfigService]
connectorService --> ssmParameterStore[AWS SSM Parameter Store]
connectorService --> secretsManager[AWS Secrets Manager]
rotatorService --> connectorService
rotatorService --> dataSource[TypeORM DataSource]
connectorModule --> typeOrmModule[TypeOrmModule.forRootAsync]
Data Flow
sequenceDiagram
participant App as NestJS App
participant Connector as ConnectorService
participant SSM as AWS Parameter Store
participant SM as AWS Secrets Manager
participant TypeORM as TypeORM DataSource
participant Rotator as RotatorService
App->>Connector: getTypeOrmOptions()
Connector->>SSM: Resolve host, port, dbName, type
SSM-->>Connector: Parameter values
Connector->>SSM: Resolve secretId
SSM-->>Connector: Secret ID
Connector->>SM: GetSecretValue(secretId)
SM-->>Connector: username + password
Connector->>SSM: Resolve optional tuning params
SSM-->>Connector: poolSize, timeouts, etc.
Connector-->>App: DataSourceOptions
App->>TypeORM: Initialize DataSource
loop Every rotation interval
Rotator->>TypeORM: Validate connection health
Rotator->>Connector: getTypeOrmOptions()
Connector->>SM: Fetch fresh credentials
SM-->>Connector: New username + password
Rotator->>TypeORM: Initialize replacement DataSource
Rotator->>TypeORM: Verify with SELECT 1
Rotator->>TypeORM: Promote replacement driver for future query runners
Rotator->>TypeORM: Retire previous pool after active query runners drain
end
📁 Project Structure
Click to expand
NestJS-TypeORM-AWS-Connector/
├── .github/
│ ├── workflows/
│ │ ├── mirror-docs-to-docviewer.yml
│ │ ├── mirror-to-codecommit.yml
│ │ ├── qodana-quality-scan.yml
│ │ ├── release.yml
│ │ ├── snyk-security-scan.yml
│ │ └── test.yml
│ └── dependabot.yml
├── docs/
│ ├── api-reference/
│ ├── getting-started/
│ └── guides/
├── scripts/
│ ├── test/
│ │ └── consumer-smoke.mjs
│ └── check-declaration-imports.cjs
├── src/
│ ├── modules/
│ │ └── typeorm-aws-connector/
│ ├── shared/
│ │ ├── constant/
│ │ ├── enum/
│ │ ├── interface/
│ │ ├── provider/
│ │ └── type/
│ └── index.ts
├── test/
│ ├── consumer/
│ └── typeorm-aws-connector/
├── CHANGELOG.md
├── commitlint.config.js
├── eslint.config.js
├── LICENSE
├── lint-staged.config.js
├── nest-cli.json
├── package-lock.json
├── package.json
├── prettier.config.js
├── README.md
├── release.config.js
├── rollup.config.js
├── tsconfig.build.json
└── tsconfig.json
📋 Prerequisites
- Node.js ^22.13.0 || >=24.11.0
- npm >= 9.0.0
- @nestjs/common and @nestjs/core >=12.3.2 <13
- @nestjs/config >=12.0.1 <13
- typeorm >=1.1.2 <2
- @elsikora/nestjs-aws-parameter-store-config ^3.0.0-dev.1 (the 3.0 prereleases and every stable 3.x)
- @aws-sdk/client-ssm >=3.535.0 <4
- AWS credentials configured (IAM role, environment variables, or AWS CLI profile)
🛠 Installation
These source docs describe Connector 3. ^3.0.0-0 selects a 3.0 prerelease and later stable 3.x releases.
# Install the connector and its peer dependencies
npm install @elsikora/nestjs-typeorm-aws-connector@^3.0.0-0 @elsikora/nestjs-aws-parameter-store-config@^3.0.0-0 @aws-sdk/client-ssm @nestjs/common@^12 @nestjs/core@^12 @nestjs/config@^12 @nestjs/typeorm@^12 typeorm@^1
The connector installs @aws-sdk/client-secrets-manager and @nestjs/schedule as direct dependencies. @elsikora/nestjs-aws-parameter-store-config and @nestjs/config are peers: the connector injects ParameterStoreConfigService and ConfigService, so it must share the application's copy of both.
Verify Installation
npm ls @elsikora/nestjs-typeorm-aws-connector @elsikora/nestjs-aws-parameter-store-config @nestjs/config typeorm
💡 Usage
Prerequisites: Register Parameter Store Config Module
Before using the connector, register ParameterStoreConfigModule from @elsikora/nestjs-aws-parameter-store-config. Register ConfigModule as global: the connector injects ConfigService inside its own module:
import { Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { ENamespace, ParameterStoreConfigModule } from "@elsikora/nestjs-aws-parameter-store-config";
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
ParameterStoreConfigModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
application: configService.getOrThrow<string>("APPLICATION"),
config: { region: configService.getOrThrow<string>("AWS_REGION") },
environment: configService.getOrThrow<string>("ENVIRONMENT"),
instanceName: "my-api",
namespace: ENamespace.AWS_ECS_FARGATE,
shouldDecryptParameters: true,
}),
}),
],
})
export class AppModule {}
Basic Usage: Static Registration
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { TypeOrmAwsConnectorModule, TypeOrmAwsConnectorService } from "@elsikora/nestjs-typeorm-aws-connector";
import { UserEntity } from "./entities/user.entity";
@Module({
imports: [
TypeOrmModule.forRootAsync({
// Register the connector inside the TypeORM factory module so the factory can inject its service
imports: [
TypeOrmAwsConnectorModule.register({
entities: [UserEntity],
rotation: {
isEnabled: false,
},
}),
],
inject: [TypeOrmAwsConnectorService],
useFactory: async (connectorService: TypeOrmAwsConnectorService) => connectorService.getTypeOrmOptions(),
}),
],
})
export class DatabaseModule {}
The connector resolves DataSourceOptions; TypeOrmModule remains the owner that initializes the live DataSource. Set rotation.isEnabled: false for one-shot processes, or see Enabling Credential Rotation for long-running services.
Custom SSM Lookups
Override where specific fields are resolved from in Parameter Store:
import { ENamespace } from "@elsikora/nestjs-aws-parameter-store-config";
import { TypeOrmAwsConnectorModule } from "@elsikora/nestjs-typeorm-aws-connector";
TypeOrmAwsConnectorModule.register({
entities: [UserEntity],
ssmLookupDefaults: {
instanceName: "my-api",
namespace: ENamespace.AWS_ECS_FARGATE,
},
ssmLookups: {
secretId: {
instanceName: "database",
namespace: ENamespace.AWS_SECRETS_MANAGER,
path: ["secret-id"],
},
host: {
instanceName: "aurora-postgres",
namespace: ENamespace.AWS_RDS,
path: ["host"],
},
port: {
instanceName: "aurora-postgres",
namespace: ENamespace.AWS_RDS,
path: ["port"],
},
rotationShutdownDrainTimeoutMs: {
path: ["database", "rotation", "shutdown-drain-timeout-ms"],
},
},
});
Local Development: Raw Value Overrides
Bypass AWS entirely for local development:
import { EDatabaseType } from "@elsikora/nestjs-typeorm-aws-connector";
TypeOrmAwsConnectorModule.register({
entities: [UserEntity],
host: "127.0.0.1",
port: 5432,
username: "local-user",
password: "local-password",
databaseName: "mydb",
type: EDatabaseType.POSTGRES,
});
Enabling Credential Rotation
Enable automatic credential rotation for long-running services:
import { Logger } from "@nestjs/common";
import { ETypeOrmAwsConnectorRotationEvent, TypeOrmAwsConnectorModule } from "@elsikora/nestjs-typeorm-aws-connector";
const rotationLogger = new Logger("DatabaseRotation");
TypeOrmAwsConnectorModule.register({
entities: [UserEntity],
rotation: {
isEnabled: true,
intervalMs: 3_600_000, // Rotate every hour
shutdownDrainTimeoutMs: 15_000,
onEvent: (event) => {
switch (event.type) {
case ETypeOrmAwsConnectorRotationEvent.DRAIN_TIMEOUT: {
rotationLogger.error("Database rotation drain timed out", event);
break;
}
case ETypeOrmAwsConnectorRotationEvent.GENERATION_RETIRED: {
rotationLogger.log("Database generation retired", event);
break;
}
case ETypeOrmAwsConnectorRotationEvent.ROTATION_DEFERRED: {
rotationLogger.warn("Database rotation deferred", event);
break;
}
}
},
},
});
When rotation is enabled, shutdownDrainTimeoutMs is required and must be a positive integer. Provide it directly or through the canonical SSM path typeorm/rotation/shutdown-drain-timeout-ms; the connector does not invent a shutdown default.
The rotation service will:
- Validate current connection health
- Fetch fresh credentials from AWS Secrets Manager
- Create a replacement
DataSourcewith schema synchronization, migrations, schema drop, and extension installation disabled - Verify the replacement connection with a
SELECT 1query - Promote the replacement driver for future query runners without destroying the live
DataSource - Keep query runners and manager-bound transactions on the generation where they started
- Defer later intervals until the one retiring generation drains and closes
- Attempt emergency recovery through the same bounded rotation gate after 3 consecutive failures
At most two database pools exist during rotation: the current generation and one retiring generation. Overlapping intervals coalesce instead of creating queued replacements.
onEvent is an optional, package-neutral observability callback. It can return void or Promise<void>; its returned promise is not awaited, and its synchronous body should stay small. It must not own correctness or database writes. Listener failures are logged only as a validated error type plus an optional SQLSTATE and are isolated from the rotation lifecycle. Event objects are frozen and contain no credentials.
The connector permanently sets TypeORM query logging to false. Foreign failure messages, stacks, SQL, parameters, driver payloads, credentials, lookup coordinates, profiles, IP addresses, and URLs are never copied into connector logs or wrapper messages. Wrapper errors retain the original failure as cause for explicit in-process handling.
| Event | Meaning |
|---|---|
ROTATION_DEFERRED | Rotation was skipped because another rotation, retirement, or shutdown prevents promotion |
GENERATION_RETIRED | A current or retiring generation closed successfully |
DRAIN_TIMEOUT | Active work did not drain, or generation close did not settle, in time |
Rotation is intended for long-lived services. For one-shot jobs, migrations, Bootstrap, or explicit CLI tasks, keep rotation.isEnabled disabled so the connector does not register a background interval.
Shutdown Lifecycle
Enable Nest shutdown hooks in long-running applications so SIGTERM reaches the connector:
const app = await NestFactory.create(AppModule);
app.enableShutdownHooks();
await app.listen(3000);
During shutdown, the connector removes its interval, refuses new query runners, waits up to shutdownDrainTimeoutMs for active work, and then closes the current, pending, and retiring generations. If drain or close does not settle, it emits DRAIN_TIMEOUT, performs best-effort cleanup, and rejects with one AggregateError; callers and orchestrators must treat that shutdown as unclean.
Drain and generation close each have a bounded phase, so the host termination budget must exceed approximately 2 × shutdownDrainTimeoutMs plus the surrounding Nest shutdown work and an operational margin.
Async Registration with Factory
TypeOrmAwsConnectorModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => {
const isRotationEnabled = configService.get<boolean>("DB_ROTATION_ENABLED", false);
return {
entities: [UserEntity],
rotation: {
intervalMs: configService.get<number>("DB_ROTATION_INTERVAL", 3_600_000),
isEnabled: isRotationEnabled,
...(isRotationEnabled
? {
shutdownDrainTimeoutMs: configService.getOrThrow<number>("DB_ROTATION_SHUTDOWN_DRAIN_TIMEOUT"),
}
: {}),
},
};
},
});
Omit the raw shutdownDrainTimeoutMs property when the enabled service should resolve it from Parameter Store instead of ConfigService.
Multiple Database Modules In One App
Register the connector separately inside each Nest database module that owns a specific TypeORM connection. The connector module is scoped to that module registration, so multiple connector instances can safely coexist in one application.
import { Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { getDataSourceToken, TypeOrmModule } from "@nestjs/typeorm";
import { TypeOrmAwsConnectorModule, TypeOrmAwsConnectorService } from "@elsikora/nestjs-typeorm-aws-connector";
import { ProviderEntity } from "./entities/provider.entity";
@Module({
imports: [
TypeOrmModule.forRootAsync({
imports: [
TypeOrmAwsConnectorModule.registerAsync({
// Must match the name below so RotatorService binds to this DataSource
dataSourceToken: getDataSourceToken("provider"),
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
entities: [ProviderEntity],
poolSize: configService.get<number>("PROVIDER_DB_POOL_SIZE", 10),
}),
}),
],
inject: [TypeOrmAwsConnectorService],
name: "provider",
useFactory: async (connectorService: TypeOrmAwsConnectorService) => connectorService.getTypeOrmOptions(),
}),
],
})
export class ProviderDatabaseModule {}
Use dataSourceToken when the connector's RotatorService should bind to a named TypeORM DataSource instead of the default connection token. Each registration owns an independent interval, generation state, and event callback.
Value Resolution Priority
For each configuration field, values are resolved in this order:
- Raw value override (provided directly in config)
- SSM Parameter Store lookup (via structured lookup)
- Built-in default (only for optional tuning fields like
poolSize,connectionTimeoutMs)
Required fields (host, port, databaseName, type, secretId) throw explicit errors if not resolvable. When rotation resolves as enabled, rotation.shutdownDrainTimeoutMs is also required. Explicit rotation properties take priority over their structured SSM lookups.
Migrating to 3.0
3.0 moves the connector to NestJS 12 and TypeORM 1 and ships it as ES modules only. The configuration API, the canonical SSM lookup contract, the rotation lifecycle and the exported names do not change.
| Requirement | 2.x | 3.0 |
|---|---|---|
| Node.js | >=20.0.0 | ^22.13.0 || >=24.11.0 |
@nestjs/common, @nestjs/core | ^8 || ^9 || ^10 || ^11 | >=12.3.2 <13 |
@nestjs/config | dependency ^4.0.3 | peer >=12.0.1 <13 |
typeorm | ^0.3.20 | >=1.1.2 <2 |
@elsikora/nestjs-aws-parameter-store-config | dependency ^2.0.2 | peer ^3.0.0-dev.1 |
@aws-sdk/client-ssm | ^3.535.0 | >=3.535.0 <4 (same range) |
| Module format | ESM and CommonJS | ESM only |
- Upgrade Node.js, NestJS and TypeORM first. Applications on NestJS 11 or older, TypeORM 0.3 or Node.js 20 stay on 2.x.
- Install
@elsikora/nestjs-aws-parameter-store-config3 and@nestjs/config12 in the application; they are no longer installed by the connector.npm lsmust show one copy of each. - Import only from the package root.
dist/esm,dist/cjsand therequireexport condition are gone.
ES module applications import the package with moduleResolution set to bundler, node16 or nodenext; the declarations carry .js extensions on every relative import. CommonJS applications keep require(), which Node.js serves through require(esm) on every supported release. TypeScript with module: commonjs finds the types through the top-level types field with moduleResolution: node10 (TypeScript 6 then needs "ignoreDeprecations": "6.0"), and through exports without moduleResolution, which TypeScript 6 resolves as bundler. Native ES module builds such as the Nest CLI SWC builder type relations between entities that import each other as Relation<T>; otherwise startup fails with ReferenceError: Cannot access '...' before initialization.
Importing the package loads no .env file and writes nothing to the console. CI checks this, and runs ESM, CommonJS and SWC consumer apps against Postgres, on the packed tarball: with the latest release in each peer range, and on Node.js 22.13.0 with every peer at the lower bound of its range.
See the complete Migrating to 3.0 guide.
Migrating from 1.x
Connector 2.0 intentionally removes the unbounded rotation and force-only shutdown contract. Existing applications that enable rotation must add a positive rotation.shutdownDrainTimeoutMs, enable Nest shutdown hooks for process signals, and decide how to surface the new structured rotation events.
See the complete Migrating to 2.0 guide before upgrading.
🛣 Roadmap
Click to expand
| Task / Feature | Status |
|---|---|
| ES module build for NestJS 12 and TypeORM 1 | ✅ Done |
| AWS Secrets Manager credential resolution | ✅ Done |
| Automatic credential rotation with staged driver promotion | ✅ Done |
| Bounded current-plus-one-retiring generation lifecycle | ✅ Done |
| Structured package-neutral rotation lifecycle events | ✅ Done |
| Emergency recovery after consecutive rotation failures | ✅ Done |
| Split-source configuration model (infra vs app namespaces) | ✅ Done |
| Raw value overrides for local development | ✅ Done |
| Async module registration with factory pattern | ✅ Done |
| Semantic release with prerelease channel | ✅ Done |
| Support for additional database types (e.g., MariaDB, CockroachDB) | 🚧 In Progress |
| Connection pool monitoring and metrics export | 🚧 In Progress |
| Read replica support with separate SSM lookups | 🚧 In Progress |
| Integration test suite with LocalStack | 🚧 In Progress |
❓ FAQ
Click to expand
❓ Frequently Asked Questions
Q: Do I need AWS credentials to use this locally? A: No! Use raw value overrides to bypass AWS entirely during local development. Set host, port, username, password, databaseName, and type directly in the config.
Q: Which databases are supported? A: Currently PostgreSQL (EDatabaseType.POSTGRES) and MySQL (EDatabaseType.MYSQL). The type field is resolved from SSM or set directly.
Q: What happens if AWS Secrets Manager is unreachable during rotation? A: The rotation service catches the error, increments a failure counter, and logs only its validated error type and optional SQLSTATE. After 3 consecutive failures, it attempts an emergency recovery with a fresh replacement connection. Failed replacements are discarded, and the currently promoted pool stays in place until a later rotation succeeds.
Q: Can I use this without @elsikora/nestjs-aws-parameter-store-config? A: No. The connector depends on ParameterStoreConfigService.get() for SSM lookups. You must register ParameterStoreConfigModule first. However, if you provide raw values for all fields, SSM lookups won't actually be invoked.
Q: How does the split-source model work? A: Infrastructure-owned fields like host, port, and secretId default to canonical AWS namespaces (e.g., aws-rds/aurora-postgres). Application-owned fields like poolSize and connectionTimeoutMs use your app's namespace (e.g., aws-ecs-fargate/my-api). You can override any lookup.
Q: Which NestJS and TypeORM versions are supported? A: 3.x needs NestJS 12 (@nestjs/common and @nestjs/core >=12.3.2 <13) and TypeORM 1 (>=1.1.2 <2) on Node.js ^22.13.0 || >=24.11.0. Applications on NestJS 8–11 or TypeORM 0.3 stay on 2.x.
Q: Can a CommonJS application use the connector? A: Yes. The package is ES modules only, and require("@elsikora/nestjs-typeorm-aws-connector") loads it through Node.js require(esm), which every supported Node.js release has without a flag.
Q: How do I disable credential rotation? A: Don't set the rotation config, or explicitly set rotation.isEnabled: false. The RotatorService will skip interval registration entirely. This is the recommended mode for one-shot jobs, migrations, and other short-lived processes.
Q: What's the default rotation interval? A: 1 hour (3,600,000 ms). Override it via rotation.intervalMs or the SSM path typeorm/rotation/interval-ms.
Q: Is there a default shutdown drain timeout? A: No. Rotation-enabled services must provide a positive integer through rotation.shutdownDrainTimeoutMs or typeorm/rotation/shutdown-drain-timeout-ms. One-shot services with rotation disabled do not require it.
Q: Can several rotations create several old pools? A: No. The connector permits one current and at most one retiring generation. Further intervals emit ROTATION_DEFERRED until the retiring generation closes.
Q: What happens to a transaction during credential rotation? A: Its query runner remains attached to the generation where it started. New query runners use the promoted generation, and ordinary rotation waits for the old pool's runners to release without applying the shutdown timeout. Forced release after shutdownDrainTimeoutMs occurs only during process shutdown.
Q: Does onEvent use Nest EventEmitter? A: No. It is an optional callback in the rotation configuration. Use it to bridge structured events into your logger, metrics, or error reporting system without adding @nestjs/event-emitter.
🔒 License
This project is licensed under MIT.
🙏 Acknowledgments
- NestJS — The progressive Node.js framework that makes building server-side applications a joy
- TypeORM — The ORM that powers the database layer with decorator-based entity definitions
- AWS SDK for JavaScript v3 — Modular AWS SDK used for SSM and Secrets Manager client operations
- @elsikora/nestjs-aws-parameter-store-config — The Parameter Store config module that provides the structured lookup foundation
- Semantic Release — Automated versioning and changelog generation
- Rollup — Module bundler powering the ES module build output
- Built with ❤️ by ElsiKora