Mongoose
This guide walks you through seeding a MongoDB database end-to-end with Mongoose and @ackplus/nest-seeder: a schema, a factory, a seeder, and the config that wires it all together.
Install
npm install @ackplus/nest-seeder @faker-js/faker
npm install @nestjs/mongoose mongooseTIP
If you write your seeder.config.ts in TypeScript, also install the dev dependencies:
npm install -D ts-node typescriptDefine a schema
Use the standard NestJS @Schema() / @Prop() decorators and export the generated schema.
// src/database/schemas/user.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument } from 'mongoose';
export type UserDocument = HydratedDocument<User>;
@Schema({ timestamps: true })
export class User {
@Prop({ required: true })
firstName: string;
@Prop({ required: true })
lastName: string;
@Prop({ required: true, unique: true })
email: string;
@Prop({ default: 'user' })
role: string;
}
export const UserSchema = SchemaFactory.createForClass(User);Create a factory
A factory is a plain class whose properties are decorated with @Factory. Each generator receives a Faker instance, and a context object (ctx) carrying override values plus any already-generated fields it depends on.
// src/database/factories/user.factory.ts
import { Factory } from '@ackplus/nest-seeder';
export class UserFactory {
@Factory((faker) => faker.person.firstName())
firstName: string;
@Factory((faker) => faker.person.lastName())
lastName: string;
@Factory(
(faker, ctx) => faker.internet.email({ firstName: ctx.firstName, lastName: ctx.lastName }).toLowerCase(),
['firstName', 'lastName'],
)
email: string;
@Factory((faker) => faker.helpers.arrayElement(['admin', 'user', 'guest']))
role: string;
}Faker v9
Use faker.number.int({ min, max }) for numbers — faker.datatype.number was removed in Faker v9. faker.datatype.boolean() is still valid.
Write a seeder
Inject the Mongoose model with @InjectModel, generate documents with DataFactory, and persist them with insertMany(). The optional drop() method clears the collection with deleteMany({}).
// src/database/seeders/user.seeder.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Seeder, SeederName, DataFactory } from '@ackplus/nest-seeder';
import { User, UserDocument } from '../schemas/user.schema';
import { UserFactory } from '../factories/user.factory';
@Injectable()
@SeederName('users')
export class UserSeeder implements Seeder {
constructor(
@InjectModel(User.name) private readonly userModel: Model<UserDocument>,
) {}
async seed(): Promise<void> {
const factory = DataFactory.createForClass(UserFactory);
const users = factory.generate(10);
await this.userModel.insertMany(users);
}
async drop(): Promise<void> {
await this.userModel.deleteMany({});
}
}INFO
drop() is optional. When present, it runs before seed() on --refresh, making your seed runs idempotent.
Configure
Create a seeder.config.ts at your project root. Register the Mongoose connection with MongooseModule.forRoot(...) and the model with MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]).
// seeder.config.ts
import { MongooseModule } from '@nestjs/mongoose';
import { defineSeederConfig } from '@ackplus/nest-seeder';
import { User, UserSchema } from './src/database/schemas/user.schema';
import { UserSeeder } from './src/database/seeders/user.seeder';
export default defineSeederConfig({
imports: [
MongooseModule.forRoot(process.env.MONGO_URI ?? 'mongodb://localhost:27017/app'),
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
seeders: [UserSeeder],
});TIP
defineSeederConfig is an identity helper — it only exists to give you full type-safety and autocompletion. It is optional but recommended.
Async config with ConfigService
If your connection string lives in environment variables managed by @nestjs/config, use MongooseModule.forRootAsync to inject the ConfigService.
// seeder.config.ts
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { defineSeederConfig } from '@ackplus/nest-seeder';
import { User, UserSchema } from './src/database/schemas/user.schema';
import { UserSeeder } from './src/database/seeders/user.seeder';
export default defineSeederConfig({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
MongooseModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
uri: config.get<string>('MONGO_URI'),
}),
}),
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
seeders: [UserSeeder],
});Run it
Add a script to package.json:
{
"scripts": {
"seed": "nest-seed"
}
}Then run the seeders:
npm run seednpm run seed -- --refreshnpm run seed -- --name usersRefresh order
On --refresh, seeders are dropped in reverse order so foreign-key-style references unwind safely. List parents first in the seeders array.
Seeding relationships
To link documents across collections, pass the referenced id as an override. Override keys do not need to be @Factory fields on the factory — they are merged into every generated object.
const factory = DataFactory.createForClass(PostFactory);
for (const user of users) {
const posts = factory.generate(3, { author: user._id }); // author is an override, not a @Factory field
await this.postModel.insertMany(posts);
}Next steps
- Factories — full
@FactoryandDataFactoryreference - Seeders — the
Seederinterface and lifecycle - CLI — every
nest-seedflag explained - DataFactory API