NestJS Dynamoose Integration
nestjs-dynamoose is a module designed to seamlessly integrate the Dynamoose ODM (Object Document Mapper) for DynamoDB into NestJS applications. It provides NestJS-specific modules and decorators that leverage NestJS's robust dependency injection system, allowing developers to define DynamoDB schemas and models in a structured, modular way. The current stable version is 0.6.0, with releases occurring frequently to maintain compatibility with new versions of NestJS and Dynamoose. Key differentiators include its adherence to NestJS architectural patterns (e.g., `forRoot`, `forFeature`), simplifying the setup and management of DynamoDB connections and models compared to integrating Dynamoose directly without the NestJS wrapper, and enabling easy configuration of AWS credentials and local DynamoDB instances.
Common errors
-
Nest can't resolve dependencies of the XService (?, YRepository)
cause The Dynamoose model was not correctly injected or the feature module was not imported.fixEnsure `DynamooseModule.forFeature()` is imported in the relevant feature module and that `InjectModel('YourModelName')` is used correctly in the service constructor, matching the name provided in `forFeature`. -
No provider for DynamooseModuleOptions! (or similar DI error related to DynamooseModule)
cause The `DynamooseModule.forRoot()` or `DynamooseModule.forRootAsync()` was not called or configured in the root `AppModule`.fixAdd `DynamooseModule.forRoot()` (or `forRootAsync()`) to the `imports` array of your main `AppModule` to initialize the Dynamoose connection. -
Type 'Schema<any, any>' is not assignable to type 'Schema<any, any>'
cause Inconsistent versions of `dynamoose` or `@types/dynamoose` in your project dependencies, often caused by transitive dependencies or different peer dependency requirements.fixCheck your `package.json` and `package-lock.json` for multiple versions of `dynamoose` or its types. Try `npm dedupe` or manually adjust versions to a single, compatible one. -
Invalid table options: Table name must be a string
cause The `tableName` option is missing or incorrectly specified in `DynamooseModule.forFeature()`'s options, or is still located in the old schema definition after v0.5.4.fixMove `tableName` from the schema definition to the `options` property within the object passed to `DynamooseModule.forFeature()`, ensuring it's a string.
Warnings
- breaking The peer dependency for NestJS has been updated multiple times, requiring users to upgrade their NestJS versions. Specifically, v0.6.0 requires NestJS 11, v0.5.5 required NestJS 10, and older versions required 8 or 9.
- breaking The `tableName` property, previously configurable directly within the schema definition, was moved to the `options` object within `DynamooseModule.forFeature()`.
- breaking The terminology `document` was renamed to `item` to align with Dynamoose v3 conventions and prevent confusion with MongoDB documents.
- breaking The peer dependency for `dynamoose` has been updated, requiring users to upgrade their `dynamoose` library. Version 0.5.6 introduced support for Dynamoose v4, and v0.5.4 added support for Dynamoose v3.2.0.
- gotcha When using `DynamooseModule.forRootAsync()`, the `useFactory` callback's first parameter is reserved for future use and should be ignored (e.g., by using `_`).
Install
-
npm install nestjs-dynamoose -
yarn add nestjs-dynamoose -
pnpm add nestjs-dynamoose
Imports
- DynamooseModule
const { DynamooseModule } = require('nestjs-dynamoose');import { DynamooseModule } from 'nestjs-dynamoose'; - Schema
import { Schema } from 'nestjs-dynamoose';import { Schema } from 'dynamoose'; - Model type
import { Model } from 'nestjs-dynamoose';import { Model } from 'dynamoose';
Quickstart
import { Module } from '@nestjs/common';
import { DynamooseModule } from 'nestjs-dynamoose';
import { Schema } from 'dynamoose';
// user/user.schema.ts
export const UserSchema = new Schema({
id: {
type: String,
hashKey: true
},
name: {
type: String
},
email: {
type: String
}
});
// user/user.service.ts (simplified)
import { Injectable } from '@nestjs/common';
import { Model } from 'dynamoose';
import { InjectModel } from 'nestjs-dynamoose';
interface UserKey { id: string; }
interface User extends UserKey { name: string; email?: string; }
@Injectable()
export class UserService {
constructor(@InjectModel('User') private userModel: Model<User, UserKey>) {}
async create(user: User): Promise<User> {
return this.userModel.create(user);
}
}
// user/user.module.ts
@Module({
imports: [
DynamooseModule.forFeature([{
name: 'User',
schema: UserSchema,
options: {
tableName: 'user-table-name' // Explicit table name
}
}])
],
providers: [UserService],
exports: [UserService]
})
export class UserModule {}
// app.module.ts
@Module({
imports: [
DynamooseModule.forRoot({
aws: {
region: process.env.AWS_REGION ?? 'us-east-1',
accessKeyId: process.env.AWS_ACCESS_KEY_ID ?? '',
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? ''
},
local: process.env.DYNAMODB_ENDPOINT ?? false // Set to true or 'http://localhost:8000' for local DynamoDB
}),
UserModule
]
})
export class AppModule {}