nestjs-boost 0.0.0-stage → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/LICENSE +21 -0
- package/NOTICE.md +6 -0
- package/README.md +168 -2
- package/bin/nestjs-boost.mjs +148 -0
- package/guidelines/core.md +64 -0
- package/lib/agents.mjs +137 -0
- package/lib/installer.mjs +450 -0
- package/lib/prompt.mjs +131 -0
- package/lib/setup.mjs +60 -0
- package/manifest.json +676 -0
- package/package.json +67 -6
- package/scripts/postinstall.mjs +49 -0
- package/skills/nestjs-ai/SKILL.md +145 -0
- package/skills/nestjs-ai/references/ai-reference.md +143 -0
- package/skills/nestjs-architecture/SKILL.md +83 -0
- package/skills/nestjs-architecture/references/dynamic-modules.md +92 -0
- package/skills/nestjs-architecture/references/scopes-lifecycle.md +98 -0
- package/skills/nestjs-architecture/references/troubleshooting.md +77 -0
- package/skills/nestjs-authentication/SKILL.md +115 -0
- package/skills/nestjs-authentication/references/flows.md +180 -0
- package/skills/nestjs-authorization/SKILL.md +104 -0
- package/skills/nestjs-caching/SKILL.md +109 -0
- package/skills/nestjs-cli-tooling/SKILL.md +94 -0
- package/skills/nestjs-cli-tooling/references/nest-cli-json.md +91 -0
- package/skills/nestjs-configuration/SKILL.md +109 -0
- package/skills/nestjs-cqrs/SKILL.md +124 -0
- package/skills/nestjs-database-drizzle/SKILL.md +117 -0
- package/skills/nestjs-database-mikro-orm/SKILL.md +109 -0
- package/skills/nestjs-database-mongoose/SKILL.md +124 -0
- package/skills/nestjs-database-prisma/SKILL.md +126 -0
- package/skills/nestjs-database-sequelize/SKILL.md +88 -0
- package/skills/nestjs-database-typeorm/SKILL.md +110 -0
- package/skills/nestjs-deployment/SKILL.md +133 -0
- package/skills/nestjs-deployment/references/serverless-and-systemd.md +133 -0
- package/skills/nestjs-events/SKILL.md +78 -0
- package/skills/nestjs-file-storage/SKILL.md +111 -0
- package/skills/nestjs-file-storage/references/storage-reference.md +82 -0
- package/skills/nestjs-graphql/SKILL.md +119 -0
- package/skills/nestjs-graphql/references/federation.md +110 -0
- package/skills/nestjs-graphql/references/schema-features.md +133 -0
- package/skills/nestjs-health-checks/SKILL.md +114 -0
- package/skills/nestjs-http-client/SKILL.md +118 -0
- package/skills/nestjs-http-client/references/http-client-reference.md +116 -0
- package/skills/nestjs-http-platform/SKILL.md +104 -0
- package/skills/nestjs-http-platform/references/adapters.md +88 -0
- package/skills/nestjs-http-web-features/SKILL.md +113 -0
- package/skills/nestjs-http-web-features/references/uploads-streaming.md +108 -0
- package/skills/nestjs-i18n/SKILL.md +113 -0
- package/skills/nestjs-idempotency/SKILL.md +112 -0
- package/skills/nestjs-locks/SKILL.md +108 -0
- package/skills/nestjs-logging/SKILL.md +123 -0
- package/skills/nestjs-mail/SKILL.md +125 -0
- package/skills/nestjs-mail/references/mail-reference.md +90 -0
- package/skills/nestjs-mcp-server/SKILL.md +152 -0
- package/skills/nestjs-mcp-server/references/mcp-reference.md +146 -0
- package/skills/nestjs-microservices/SKILL.md +108 -0
- package/skills/nestjs-microservices/references/transports.md +117 -0
- package/skills/nestjs-observability/SKILL.md +108 -0
- package/skills/nestjs-observability/references/apm-and-otel.md +106 -0
- package/skills/nestjs-openapi/SKILL.md +90 -0
- package/skills/nestjs-openapi/references/swagger-reference.md +180 -0
- package/skills/nestjs-outbox/SKILL.md +119 -0
- package/skills/nestjs-outbox/references/outbox-reference.md +74 -0
- package/skills/nestjs-passport-auth/SKILL.md +125 -0
- package/skills/nestjs-queues/SKILL.md +118 -0
- package/skills/nestjs-queues/references/bull-legacy.md +75 -0
- package/skills/nestjs-request-pipeline/SKILL.md +146 -0
- package/skills/nestjs-request-pipeline/references/filters-interceptors.md +114 -0
- package/skills/nestjs-request-pipeline/references/pipes-decorators.md +80 -0
- package/skills/nestjs-resilience/SKILL.md +116 -0
- package/skills/nestjs-resilience/references/resilience-reference.md +74 -0
- package/skills/nestjs-scheduling/SKILL.md +100 -0
- package/skills/nestjs-security-hardening/SKILL.md +99 -0
- package/skills/nestjs-security-hardening/references/throttler-advanced.md +78 -0
- package/skills/nestjs-standalone-apps/SKILL.md +78 -0
- package/skills/nestjs-testing/SKILL.md +118 -0
- package/skills/nestjs-testing/references/advanced-testing.md +62 -0
- package/skills/nestjs-upgrading/SKILL.md +82 -0
- package/skills/nestjs-upgrading/references/esm-switch.md +114 -0
- package/skills/nestjs-validation-serialization/SKILL.md +124 -0
- package/skills/nestjs-validation-serialization/references/validation-options.md +84 -0
- package/skills/nestjs-webhooks/SKILL.md +116 -0
- package/skills/nestjs-webhooks/references/webhooks-reference.md +132 -0
- package/skills/nestjs-websockets/SKILL.md +108 -0
- package/skills/nestjs-workflows/SKILL.md +123 -0
- package/skills/nestjs-workflows/references/workflows-reference.md +85 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nestjs-database-mikro-orm
|
|
3
|
+
description: Integrates MikroORM v7 with NestJS 12 through @mikro-orm/nestjs — MikroOrmModule.forRoot/forRootAsync (driver beside useFactory), legacy decorators from @mikro-orm/decorators/legacy with ReflectMetadataProvider, entities and Rel relation wrappers, forFeature repositories and custom repositories, autoLoadEntities, the per-request EntityManager context middleware, @CreateRequestContext for queues and cron jobs, em.transactional and @Transactional, MikroORM serialization instead of ClassSerializerInterceptor, multiple contexts, shutdown hooks, and test mocks with getRepositoryToken. Use when the project uses or wants MikroORM, when adding entities, repositories, flush/transactions, or when the global EntityManager throws a ValidationError outside a request context, missing decorator exports after upgrading to v7, or broken relation JSON. Not for TypeORM, Drizzle, Prisma, Mongoose or Sequelize (their own skills).
|
|
4
|
+
compatibility: NestJS 12.x; MikroORM v7, @mikro-orm/nestjs v7 (third-party, maintained by the MikroORM team), a @mikro-orm driver package
|
|
5
|
+
metadata:
|
|
6
|
+
version: "0.1.0"
|
|
7
|
+
nestjs-major: "12"
|
|
8
|
+
docs-crawled: "2026-11-05"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# NestJS + MikroORM v7
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i @mikro-orm/nestjs @mikro-orm/core @mikro-orm/decorators @mikro-orm/postgresql # or sqlite, mysql, mongodb…
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`@mikro-orm/nestjs` is maintained by the MikroORM team. v7 changes: decorators moved to `@mikro-orm/decorators/legacy`, `ReflectMetadataProvider` is no longer the default, and `forRoot()` needs an explicit config.
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// mikro-orm.config.ts — shared with the MikroORM CLI
|
|
23
|
+
import { ReflectMetadataProvider } from '@mikro-orm/decorators/legacy';
|
|
24
|
+
import { defineConfig } from '@mikro-orm/postgresql';
|
|
25
|
+
export default defineConfig({
|
|
26
|
+
clientUrl: process.env.DATABASE_URL,
|
|
27
|
+
entities: ['./dist/**/*.entity.js'],
|
|
28
|
+
entitiesTs: ['./src/**/*.entity.ts'],
|
|
29
|
+
metadataProvider: ReflectMetadataProvider, // required with legacy decorators
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// app.module.ts — async variant
|
|
33
|
+
MikroOrmModule.forRootAsync({
|
|
34
|
+
driver: PostgreSqlDriver, // beside useFactory, not inside: registers driver-specific tokens
|
|
35
|
+
inject: [ConfigService],
|
|
36
|
+
useFactory: (config: ConfigService) => ({ clientUrl: config.getOrThrow('DATABASE_URL'), autoLoadEntities: true, metadataProvider: ReflectMetadataProvider }),
|
|
37
|
+
}),
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- Nest-specific options: `autoLoadEntities`, `registerRequestContext` (true), `forRoutesPath`, `scope`, `contextName`.
|
|
41
|
+
- Inject `MikroORM` and `EntityManager` from **your driver package** (`@mikro-orm/postgresql`) for the driver-specific API.
|
|
42
|
+
- `autoLoadEntities` skips relation-only entities and doesn't affect the CLI (keep globs there). Base entities go in config, not `forFeature()`.
|
|
43
|
+
- Call `app.enableShutdownHooks()` so the ORM closes on SIGTERM.
|
|
44
|
+
|
|
45
|
+
## Entities and repositories
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
@Entity({ repository: () => BookRepository })
|
|
49
|
+
export class Book {
|
|
50
|
+
[EntityRepositoryType]?: BookRepository;
|
|
51
|
+
@PrimaryKey() id: number;
|
|
52
|
+
@Property() title: string;
|
|
53
|
+
@ManyToOne(() => Author) author: Rel<Author>; // Rel<T>/Ref<T> avoids circular metadata at runtime
|
|
54
|
+
@Property({ hidden: true }) internalNote?: string; // excluded from JSON
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class BookRepository extends EntityRepository<Book> {
|
|
58
|
+
findByTitle(title: string) { return this.findOne({ title }); }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@Module({ imports: [MikroOrmModule.forFeature([Book])], providers: [BooksService] })
|
|
62
|
+
export class BooksModule {}
|
|
63
|
+
|
|
64
|
+
@Injectable()
|
|
65
|
+
export class BooksService {
|
|
66
|
+
constructor(private readonly books: BookRepository, private readonly em: EntityManager) {} // custom repo injected by class
|
|
67
|
+
async create(title: string, authorId: number) {
|
|
68
|
+
const book = this.em.create(Book, { title, author: authorId });
|
|
69
|
+
await this.em.flush(); // repositories have no persist/flush
|
|
70
|
+
return book;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Default repositories: `@InjectRepository(Photo) repo: EntityRepository<Photo>`.
|
|
76
|
+
|
|
77
|
+
## Request context (identity map per request)
|
|
78
|
+
|
|
79
|
+
- HTTP requests get a forked `EntityManager` from the module's middleware automatically.
|
|
80
|
+
- Outside HTTP (queue processors, `@Cron`, event listeners, microservice handlers) the global EM throws a `ValidationError` for `find()`/`flush()`. Decorate the method with `@CreateRequestContext()` (directly above the method, **below** `@Cron()`/`@Process()` etc.); the class needs an `orm` or `em` property. `@EnsureRequestContext()` reuses an existing context.
|
|
81
|
+
- Alternative: `registerRequestContext: false, scope: Scope.REQUEST` — makes every EM consumer request-scoped (slower).
|
|
82
|
+
|
|
83
|
+
## Transactions
|
|
84
|
+
|
|
85
|
+
- `em.flush()` already wraps queued writes in one transaction.
|
|
86
|
+
- Explicit: `await this.em.transactional(async (em) => { em.create(Photo, { name }); })` (forked EM; flushed and committed when the callback resolves; nested calls use savepoints).
|
|
87
|
+
- Decorator: `@Transactional()` on an async method of a class with `em`/`orm`.
|
|
88
|
+
|
|
89
|
+
## Serialization
|
|
90
|
+
|
|
91
|
+
Don't use `ClassSerializerInterceptor` (class-transformer) with MikroORM entities: it mangles relation wrappers. Use entity options (`hidden: true`, `persist: false`, serializers), `serialize(entity, { populate, exclude, fields, groups })`, or `wrap(entity).toObject()`.
|
|
92
|
+
|
|
93
|
+
## Multiple databases
|
|
94
|
+
|
|
95
|
+
One `forRoot()` per database with a unique `contextName` and `registerRequestContext: false` on each (with `forRootAsync`, `contextName` beside `useFactory`). Then `forFeature([Album], 'albums')`, `@InjectRepository(Album, 'albums')`, `@InjectEntityManager('albums')`, `@InjectMikroORM('albums')`, `@InjectMikroORMs()`.
|
|
96
|
+
|
|
97
|
+
## Testing
|
|
98
|
+
|
|
99
|
+
`{ provide: getRepositoryToken(Photo), useValue: mockRepo }` (or the custom repository class as token) and `{ provide: EntityManager, useValue: mockEm }`. For multiple contexts: `getRepositoryToken(Album, 'albums')`.
|
|
100
|
+
|
|
101
|
+
## Workflow
|
|
102
|
+
|
|
103
|
+
- [ ] 1. Install core, decorators, driver and `@mikro-orm/nestjs`; write `mikro-orm.config.ts` with `ReflectMetadataProvider`.
|
|
104
|
+
- [ ] 2. Register `forRoot(config)` or `forRootAsync({ driver, useFactory })`; enable shutdown hooks.
|
|
105
|
+
- [ ] 3. Entities with legacy decorators and `Rel<T>`; `forFeature` per module; writes through `em` + `flush`.
|
|
106
|
+
- [ ] 4. Add `@CreateRequestContext()` to every non-HTTP entry point that touches the EM.
|
|
107
|
+
- [ ] 5. Migrations via the MikroORM CLI using the same config. Build, lint, run tests, start the app.
|
|
108
|
+
|
|
109
|
+
Sources: [MikroORM](https://docs.nestjs.com/data/mikroorm)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nestjs-database-mongoose
|
|
3
|
+
description: Integrates MongoDB with NestJS 12 through @nestjs/mongoose — MongooseModule.forRoot/forRootAsync, decorator schemas with @Schema/@Prop/SchemaFactory and HydratedDocument types, references and typed populate, raw() nested objects, subdocuments and DocumentArray types, @Virtual properties, forFeature models injected with @InjectModel, hooks and plugins via forFeatureAsync or connectionFactory, discriminators, transactions with connection.startSession(), multiple named connections, connection events with onConnectionCreate, and mocking models with getModelToken. Use when the project uses or wants MongoDB/Mongoose, when adding a schema, model, populate, middleware hook or transaction, or when seeing model injection errors. Not for SQL ORMs (TypeORM, Drizzle, Prisma, MikroORM, Sequelize skills) or MongoDB via TypeORM (nestjs-database-typeorm).
|
|
4
|
+
compatibility: NestJS 12.x; @nestjs/mongoose, mongoose
|
|
5
|
+
metadata:
|
|
6
|
+
version: "0.1.0"
|
|
7
|
+
nestjs-major: "12"
|
|
8
|
+
docs-crawled: "2026-11-05"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# NestJS + Mongoose
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i @nestjs/mongoose mongoose
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// app.module.ts
|
|
21
|
+
MongooseModule.forRootAsync({
|
|
22
|
+
inject: [ConfigService],
|
|
23
|
+
useFactory: (config: ConfigService) => ({
|
|
24
|
+
uri: config.getOrThrow<string>('MONGODB_URI'),
|
|
25
|
+
onConnectionCreate: (connection: Connection) => {
|
|
26
|
+
connection.on('disconnected', () => logger.warn('MongoDB disconnected'));
|
|
27
|
+
return connection;
|
|
28
|
+
},
|
|
29
|
+
}),
|
|
30
|
+
}),
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`forRoot(uri, options)` takes `mongoose.connect()` options plus Nest extras (`connectionName`, `connectionFactory`, `onConnectionCreate`).
|
|
34
|
+
|
|
35
|
+
## Schema → model → service
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// cats/schemas/cat.schema.ts
|
|
39
|
+
export type CatDocument = HydratedDocument<Cat>;
|
|
40
|
+
|
|
41
|
+
@Schema({ timestamps: true }) // collection: "cats"
|
|
42
|
+
export class Cat {
|
|
43
|
+
@Prop({ required: true }) name: string;
|
|
44
|
+
@Prop() age: number;
|
|
45
|
+
@Prop([String]) tags: string[];
|
|
46
|
+
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Owner' }) owner: mongoose.Types.ObjectId; // not always populated
|
|
47
|
+
@Prop(raw({ firstName: { type: String }, lastName: { type: String } })) details: Record<string, any>;
|
|
48
|
+
@Virtual({ get: function (this: Cat) { return `${this.name} (${this.age})`; } }) label: string;
|
|
49
|
+
}
|
|
50
|
+
export const CatSchema = SchemaFactory.createForClass(Cat);
|
|
51
|
+
|
|
52
|
+
// cats/cats.module.ts
|
|
53
|
+
@Module({ imports: [MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }])], providers: [CatsService] })
|
|
54
|
+
export class CatsModule {}
|
|
55
|
+
|
|
56
|
+
// cats/cats.service.ts
|
|
57
|
+
@Injectable()
|
|
58
|
+
export class CatsService {
|
|
59
|
+
constructor(@InjectModel(Cat.name) private readonly catModel: Model<Cat>) {}
|
|
60
|
+
create(dto: CreateCatDto) { return new this.catModel(dto).save(); }
|
|
61
|
+
findAll() { return this.catModel.find().lean().exec(); }
|
|
62
|
+
findWithOwner(id: string) { return this.catModel.findById(id).populate<{ owner: Owner }>('owner').exec(); }
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- Keep schemas next to their domain module. To share a model, export `MongooseModule` from the owning module (or export a service).
|
|
67
|
+
- Type references as `ObjectId` unless always populated, then populate with an explicit generic.
|
|
68
|
+
- Subdocuments: `@Prop(NameSchema) name: Name` with `HydratedDocument<Person, { name: Types.Subdocument<Types.ObjectId> & Name }>`; arrays: `@Prop([NameSchema])` with `Types.DocumentArray<Name>`.
|
|
69
|
+
- Validate request input with DTOs/schemas (nestjs-validation-serialization) — Mongoose validation is a second line, not the API contract. Validate id parameters (e.g. a 24-hex-character rule in your schema/DTO) before querying, so malformed ids get a 400 instead of a Mongoose `CastError` 500.
|
|
70
|
+
|
|
71
|
+
## Hooks, plugins, discriminators
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
MongooseModule.forFeatureAsync([{
|
|
75
|
+
name: Cat.name,
|
|
76
|
+
imports: [ConfigModule], inject: [ConfigService],
|
|
77
|
+
useFactory: (config: ConfigService) => {
|
|
78
|
+
const schema = CatSchema;
|
|
79
|
+
schema.pre('save', function () { /* … */ });
|
|
80
|
+
schema.plugin(autopopulate);
|
|
81
|
+
return schema;
|
|
82
|
+
},
|
|
83
|
+
}]),
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- Global plugins: `forRoot(uri, { connectionFactory: (conn) => { conn.plugin(p); return conn; } })` (before models are created).
|
|
87
|
+
- Discriminators: base schema with `discriminatorKey: 'kind'`, then `forFeature([{ name: Event.name, schema: EventSchema, discriminators: [{ name: SignUpEvent.name, schema: SignUpEventSchema }] }])`.
|
|
88
|
+
- `DefinitionsFactory.createForClass(Cat)` gives a raw definition to tweak by hand.
|
|
89
|
+
|
|
90
|
+
## Transactions
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
constructor(@InjectConnection() private readonly connection: Connection) {}
|
|
94
|
+
|
|
95
|
+
async transfer() {
|
|
96
|
+
const session = await this.connection.startSession();
|
|
97
|
+
try {
|
|
98
|
+
await session.withTransaction(async () => {
|
|
99
|
+
await this.accounts.updateOne({ _id: a }, { $inc: { balance: -10 } }, { session });
|
|
100
|
+
await this.accounts.updateOne({ _id: b }, { $inc: { balance: 10 } }, { session });
|
|
101
|
+
});
|
|
102
|
+
} finally { await session.endSession(); }
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Start sessions from the injected connection, not `mongoose.startSession()`. Transactions need a replica set (or Atlas).
|
|
107
|
+
|
|
108
|
+
## Multiple connections
|
|
109
|
+
|
|
110
|
+
`forRoot(uri, { connectionName: 'cats' })` (names are mandatory with several connections), `forFeature([...], 'cats')`, `@InjectModel(Cat.name, 'cats')`, `@InjectConnection('cats')`, `getConnectionToken('cats')`, `getModelToken(Cat.name, 'cats')`.
|
|
111
|
+
|
|
112
|
+
## Testing
|
|
113
|
+
|
|
114
|
+
Unit: `{ provide: getModelToken(Cat.name), useValue: { find: vi.fn().mockReturnValue({ exec: vi.fn() }) } }`. Integration: `mongodb-memory-server` or a Testcontainers MongoDB (replica set if you use transactions).
|
|
115
|
+
|
|
116
|
+
## Workflow
|
|
117
|
+
|
|
118
|
+
- [ ] 1. Install; `forRootAsync` from validated config.
|
|
119
|
+
- [ ] 2. Schema class + `SchemaFactory`; `forFeature` in the feature module; inject the model.
|
|
120
|
+
- [ ] 3. Add indexes (`@Prop({ index: true })` / `schema.index()`), hooks, discriminators as needed.
|
|
121
|
+
- [ ] 4. Tests with `getModelToken` mocks; e2e against a real/in-memory MongoDB.
|
|
122
|
+
- [ ] 5. Build, lint, run tests, start the app.
|
|
123
|
+
|
|
124
|
+
Sources: [MongoDB](https://docs.nestjs.com/data/mongodb)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nestjs-database-prisma
|
|
3
|
+
description: Integrates Prisma ORM 7 with NestJS 12 — installing prisma@7 with a driver adapter (better-sqlite3, pg, mariadb, mssql), prisma init with a generated client inside src, ESM vs CJS moduleFormat, schema models and prisma migrate dev, prisma generate in CI, a PrismaService extending PrismaClient with the adapter and $connect/$disconnect lifecycle hooks, a PrismaModule, typed CRUD services with generated Prisma types, sequential and interactive $transaction, and mocking PrismaService in tests. Use when the project uses or wants Prisma, when adding a model, migration, query or transaction with Prisma, or when hitting Prisma 7 setup errors (missing adapter, wrong prisma CLI version, generated client not found, import.meta in CommonJS, beforeExit hooks). Not for TypeORM, Drizzle, Mongoose, MikroORM or Sequelize (their own skills).
|
|
4
|
+
compatibility: NestJS 12.x; prisma@7 and @prisma/client@7 with an @prisma/adapter-* package; @nestjs/config
|
|
5
|
+
metadata:
|
|
6
|
+
version: "0.1.0"
|
|
7
|
+
nestjs-major: "12"
|
|
8
|
+
docs-crawled: "2026-11-05"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# NestJS + Prisma 7
|
|
12
|
+
|
|
13
|
+
Prisma has no Nest package: you wrap the generated client in a provider.
|
|
14
|
+
|
|
15
|
+
## Install (pin Prisma 7)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm i -D prisma@7 dotenv
|
|
19
|
+
npm i @prisma/client@7 @prisma/adapter-pg # or adapter-better-sqlite3 | adapter-mariadb | adapter-mssql
|
|
20
|
+
npx prisma init --datasource-provider postgresql --output ../src/generated/prisma
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- **Install `prisma@7` explicitly**: `latest` may point at a Prisma 8 pre-release without `migrate`/`generate`.
|
|
24
|
+
- `init` creates `prisma/schema.prisma`, the Prisma config file in the project root (`prisma7.config.ts`; `prisma.config.ts` before 7.10) and `.env`, and git-ignores the generated client.
|
|
25
|
+
- The client is generated into `src/generated/prisma` and compiled with the app. ESM projects (the v12 default) need nothing else; CommonJS projects set `moduleFormat = "cjs"` in the generator (the ESM client uses `import.meta`).
|
|
26
|
+
- The connection URL lives in `DATABASE_URL`, read by the Prisma config file; the app reads it through `ConfigService` (`ConfigModule.forRoot({ isGlobal: true })`).
|
|
27
|
+
|
|
28
|
+
## Models and migrations
|
|
29
|
+
|
|
30
|
+
```groovy
|
|
31
|
+
generator client {
|
|
32
|
+
provider = "prisma-client"
|
|
33
|
+
output = "../src/generated/prisma"
|
|
34
|
+
}
|
|
35
|
+
datasource db { provider = "postgresql" }
|
|
36
|
+
|
|
37
|
+
model User {
|
|
38
|
+
id Int @id @default(autoincrement())
|
|
39
|
+
email String @unique
|
|
40
|
+
posts Post[]
|
|
41
|
+
}
|
|
42
|
+
model Post {
|
|
43
|
+
id Int @id @default(autoincrement())
|
|
44
|
+
title String
|
|
45
|
+
author User? @relation(fields: [authorId], references: [id])
|
|
46
|
+
authorId Int?
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- `npx prisma migrate dev --name init` creates and applies SQL migrations (development). Deploy with `npx prisma migrate deploy` in the release step.
|
|
51
|
+
- `npx prisma generate` after every schema change — `migrate dev` doesn't run it — and **in CI/fresh checkouts before `nest build`**, since the client isn't committed. Add it to a `prebuild` script.
|
|
52
|
+
|
|
53
|
+
## PrismaService and PrismaModule
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// src/prisma/prisma.service.ts
|
|
57
|
+
import { PrismaPg } from '@prisma/adapter-pg';
|
|
58
|
+
import { PrismaClient } from '../generated/prisma/client.js';
|
|
59
|
+
|
|
60
|
+
@Injectable()
|
|
61
|
+
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
|
62
|
+
constructor(config: ConfigService) {
|
|
63
|
+
super({ adapter: new PrismaPg({ connectionString: config.getOrThrow<string>('DATABASE_URL') }) }); // adapter is required in v7
|
|
64
|
+
}
|
|
65
|
+
async onModuleInit() { await this.$connect(); } // fail at startup, not on first request
|
|
66
|
+
async onModuleDestroy() { await this.$disconnect(); } // also closes the adapter's pool
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/prisma/prisma.module.ts
|
|
70
|
+
@Module({ providers: [PrismaService], exports: [PrismaService] })
|
|
71
|
+
export class PrismaModule {}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- Call `app.enableShutdownHooks()` in `main.ts`; Prisma 7 has no `$on('beforeExit')`.
|
|
75
|
+
- Import `PrismaModule` where needed, or mark it `@Global()` if nearly every module uses it.
|
|
76
|
+
|
|
77
|
+
## Queries and transactions
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { Prisma, User } from '../generated/prisma/client.js';
|
|
81
|
+
|
|
82
|
+
@Injectable()
|
|
83
|
+
export class UsersService {
|
|
84
|
+
constructor(private readonly prisma: PrismaService) {}
|
|
85
|
+
user(where: Prisma.UserWhereUniqueInput): Promise<User | null> { return this.prisma.user.findUnique({ where }); }
|
|
86
|
+
|
|
87
|
+
async page(skip: number, take: number) {
|
|
88
|
+
const [posts, total] = await this.prisma.$transaction([ // sequential, one transaction
|
|
89
|
+
this.prisma.post.findMany({ skip, take }), this.prisma.post.count(),
|
|
90
|
+
]);
|
|
91
|
+
return { posts, total };
|
|
92
|
+
}
|
|
93
|
+
deleteWithPosts(id: number) {
|
|
94
|
+
return this.prisma.$transaction(async (tx) => { // interactive: use tx for every query
|
|
95
|
+
await tx.post.deleteMany({ where: { authorId: id } });
|
|
96
|
+
return tx.user.delete({ where: { id } });
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- Nested writes are transactional automatically. `$transaction(…, { maxWait, timeout, isolationLevel })`.
|
|
103
|
+
- Generated types are compile-time only: validate request bodies with DTOs or schemas (nestjs-validation-serialization), not Prisma types.
|
|
104
|
+
- Map known errors (unique violation `P2002`, not found `P2025`) to HTTP exceptions in the service or an exception filter.
|
|
105
|
+
- Decorator-based transactions across services: `nestjs-cls` transactional plugin with the Prisma adapter.
|
|
106
|
+
- Packages with stores (`@nestjs/outbox`, `@nestjs/webhooks`) use `fromPrisma(prisma)` and need the driver adapter client.
|
|
107
|
+
|
|
108
|
+
## Testing
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const moduleRef = await Test.createTestingModule({
|
|
112
|
+
providers: [UsersService, { provide: PrismaService, useValue: { user: { findUnique: vi.fn() } } }],
|
|
113
|
+
}).compile();
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The mock replaces the class, so `onModuleInit` never connects. For module-level tests use `.overrideProvider(PrismaService)`. Run integration tests against a real database with `prisma migrate deploy` applied.
|
|
117
|
+
|
|
118
|
+
## Workflow
|
|
119
|
+
|
|
120
|
+
- [ ] 1. Install pinned Prisma 7 + adapter; `prisma init` with `--output ../src/generated/prisma`.
|
|
121
|
+
- [ ] 2. Write models; `prisma migrate dev`; `prisma generate`; add `prisma generate` to the build pipeline.
|
|
122
|
+
- [ ] 3. Add `PrismaService` (adapter + lifecycle) and `PrismaModule`; `enableShutdownHooks()`.
|
|
123
|
+
- [ ] 4. Services with generated types; transactions via `$transaction`.
|
|
124
|
+
- [ ] 5. Tests with a `PrismaService` mock. Build, lint, run tests, start the app.
|
|
125
|
+
|
|
126
|
+
Sources: [Prisma](https://docs.nestjs.com/data/prisma)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nestjs-database-sequelize
|
|
3
|
+
description: Integrates Sequelize with NestJS 12 through @nestjs/sequelize and sequelize-typescript — SequelizeModule.forRoot/forRootAsync, Active Record models with @Table/@Column extending Model, associations (@HasMany, @BelongsTo, @BelongsToMany), forFeature with @InjectModel(User) typed as typeof User, autoLoadModels and synchronize, managed transactions with sequelize.transaction(), migrations with the Sequelize CLI, multiple named connections, connection retries and mocking models with getModelToken. Use when the project uses or wants Sequelize, when adding a model, association, transaction or migration, or when models aren't registered or injected. Not for TypeORM, Drizzle, Prisma, Mongoose or MikroORM (their own skills).
|
|
4
|
+
compatibility: NestJS 12.x; @nestjs/sequelize, sequelize, sequelize-typescript, a dialect driver (mysql2, pg, …)
|
|
5
|
+
metadata:
|
|
6
|
+
version: "0.1.0"
|
|
7
|
+
nestjs-major: "12"
|
|
8
|
+
docs-crawled: "2026-11-05"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# NestJS + Sequelize
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i @nestjs/sequelize sequelize sequelize-typescript pg # or mysql2, …
|
|
15
|
+
npm i -D @types/sequelize
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Setup
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
SequelizeModule.forRootAsync({
|
|
22
|
+
inject: [ConfigService],
|
|
23
|
+
useFactory: (config: ConfigService) => ({
|
|
24
|
+
dialect: 'postgres',
|
|
25
|
+
uri: config.getOrThrow<string>('DATABASE_URL'),
|
|
26
|
+
autoLoadModels: true, // models registered with forFeature()
|
|
27
|
+
synchronize: false, // default true with autoLoadModels — turn off outside throwaway dev databases
|
|
28
|
+
}),
|
|
29
|
+
}),
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Extra options beside the Sequelize constructor's: `retryAttempts` (10), `retryDelay` (3000), `autoLoadModels` (false), `autoCloseConnection` (true), `synchronize` (true). Inject `Sequelize` (from `sequelize-typescript`) anywhere.
|
|
33
|
+
|
|
34
|
+
## Models (Active Record)
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
@Table
|
|
38
|
+
export class User extends Model {
|
|
39
|
+
@Column firstName: string;
|
|
40
|
+
@Column({ defaultValue: true }) isActive: boolean;
|
|
41
|
+
@HasMany(() => Photo) photos: Photo[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@Module({ imports: [SequelizeModule.forFeature([User])], providers: [UsersService] })
|
|
45
|
+
export class UsersModule {}
|
|
46
|
+
|
|
47
|
+
@Injectable()
|
|
48
|
+
export class UsersService {
|
|
49
|
+
constructor(@InjectModel(User) private readonly userModel: typeof User) {}
|
|
50
|
+
findOne(id: string) { return this.userModel.findOne({ where: { id }, include: [Photo] }); }
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- Keep models in their domain module. To use a model in another module, export `SequelizeModule` from the owning module.
|
|
55
|
+
- `autoLoadModels` skips models only referenced through associations: register every model via `forFeature()` (or list them in `models`).
|
|
56
|
+
|
|
57
|
+
## Transactions (managed)
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
await this.sequelize.transaction(async (t) => {
|
|
61
|
+
const opts = { transaction: t };
|
|
62
|
+
await this.userModel.create({ firstName: 'Ada' }, opts);
|
|
63
|
+
await this.photoModel.create({ userId: 1 }, opts);
|
|
64
|
+
}); // commits when the callback resolves, rolls back on throw
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Pass `{ transaction: t }` to every call. For testability, hide `sequelize.transaction` behind a small injectable factory instead of mocking `Sequelize`.
|
|
68
|
+
|
|
69
|
+
## Migrations
|
|
70
|
+
|
|
71
|
+
Sequelize CLI migrations live outside the Nest app (no DI). Use them instead of `synchronize` for anything with data you care about; keep CLI config reading the same env vars.
|
|
72
|
+
|
|
73
|
+
## Multiple databases
|
|
74
|
+
|
|
75
|
+
Name every non-default connection (`name: 'albumsConnection'`, beside `useFactory` for async), then `forFeature([Album], 'albumsConnection')`, `@InjectModel(Album, 'albumsConnection')`, `@InjectConnection('albumsConnection')`, `getConnectionToken('albumsConnection')`. Unnamed connections override each other.
|
|
76
|
+
|
|
77
|
+
## Testing
|
|
78
|
+
|
|
79
|
+
`{ provide: getModelToken(User), useValue: { findAll: vi.fn(), findOne: vi.fn() } }`.
|
|
80
|
+
|
|
81
|
+
## Workflow
|
|
82
|
+
|
|
83
|
+
- [ ] 1. Install; `forRootAsync` from validated config; decide `synchronize: false` + CLI migrations.
|
|
84
|
+
- [ ] 2. Model class with decorators; `forFeature` in its module; `@InjectModel(Model)` typed `typeof Model`.
|
|
85
|
+
- [ ] 3. Wrap multi-step writes in `sequelize.transaction`.
|
|
86
|
+
- [ ] 4. Tests with `getModelToken` mocks. Build, lint, run tests, start the app.
|
|
87
|
+
|
|
88
|
+
Sources: [Sequelize](https://docs.nestjs.com/data/sequelize)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nestjs-database-typeorm
|
|
3
|
+
description: Integrates TypeORM with NestJS 12 through @nestjs/typeorm — TypeOrmModule.forRoot/forRootAsync with ConfigService, entities and relations, autoLoadEntities, forFeature repositories with @InjectRepository, EntitySchema definitions, transactions with DataSource.transaction or QueryRunner, entity subscribers, migrations outside the Nest container, multiple named data sources, custom dataSourceFactory, connection retries, and mocking repositories with getRepositoryToken in tests. Use when the project uses or wants TypeORM (MySQL, PostgreSQL, SQLite, MariaDB, MSSQL), when adding an entity, repository, relation, transaction or migration, or when seeing "Nest can't resolve dependencies of XService (UserRepository)", missing entity metadata or data source naming problems. Not for Drizzle, Prisma, Mongoose, MikroORM or Sequelize (their own skills) or caching (nestjs-caching).
|
|
4
|
+
compatibility: NestJS 12.x; @nestjs/typeorm, typeorm and a driver (pg, mysql2, better-sqlite3, …)
|
|
5
|
+
metadata:
|
|
6
|
+
version: "0.1.0"
|
|
7
|
+
nestjs-major: "12"
|
|
8
|
+
docs-crawled: "2026-11-05"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# NestJS + TypeORM
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i @nestjs/typeorm typeorm pg # or mysql2, better-sqlite3, …
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Default setup
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// app.module.ts
|
|
21
|
+
TypeOrmModule.forRootAsync({
|
|
22
|
+
inject: [ConfigService],
|
|
23
|
+
useFactory: (config: ConfigService) => ({
|
|
24
|
+
type: 'postgres',
|
|
25
|
+
url: config.getOrThrow<string>('DATABASE_URL'),
|
|
26
|
+
autoLoadEntities: true, // entities registered via forFeature()
|
|
27
|
+
synchronize: false, // never true in production: can drop data
|
|
28
|
+
migrations: ['dist/migrations/*.js'],
|
|
29
|
+
}),
|
|
30
|
+
}),
|
|
31
|
+
|
|
32
|
+
// users/user.entity.ts
|
|
33
|
+
@Entity()
|
|
34
|
+
export class User {
|
|
35
|
+
@PrimaryGeneratedColumn('uuid') id: string;
|
|
36
|
+
@Column({ unique: true }) email: string;
|
|
37
|
+
@OneToMany(() => Photo, (photo) => photo.user) photos: Photo[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// users/users.module.ts
|
|
41
|
+
@Module({ imports: [TypeOrmModule.forFeature([User])], providers: [UsersService], exports: [UsersService] })
|
|
42
|
+
export class UsersModule {}
|
|
43
|
+
|
|
44
|
+
// users/users.service.ts
|
|
45
|
+
@Injectable()
|
|
46
|
+
export class UsersService {
|
|
47
|
+
constructor(@InjectRepository(User) private readonly users: Repository<User>) {}
|
|
48
|
+
findOne(id: string) { return this.users.findOneBy({ id }); }
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- Each feature module registers its own entities with `forFeature([...])`. To use a repository in another module, export `TypeOrmModule` from the owning module (or better, export a service).
|
|
53
|
+
- `autoLoadEntities` skips entities only referenced through relations: register every entity with some `forFeature()`.
|
|
54
|
+
- Extra module options: `retryAttempts` (10), `retryDelay` (3000 ms), `toRetry(err)`, `verboseRetryLog`, `manualInitialization`.
|
|
55
|
+
- Inject `DataSource` / `EntityManager` directly when needed (from `typeorm`).
|
|
56
|
+
|
|
57
|
+
## Transactions
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
async transfer(from: string, to: string, amount: number) {
|
|
61
|
+
await this.dataSource.transaction(async (manager) => {
|
|
62
|
+
await manager.decrement(Account, { id: from }, 'balance', amount);
|
|
63
|
+
await manager.increment(Account, { id: to }, 'balance', amount);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Use the `manager` passed to the callback for every statement in the transaction (repositories injected with `@InjectRepository` are outside it; use `manager.getRepository(Entity)`). For manual control use `dataSource.createQueryRunner()` → `connect()` → `startTransaction()` → `commitTransaction()` / `rollbackTransaction()` → `release()` in `finally`. For unit-testability, wrap QueryRunner creation in a small injectable factory instead of mocking `DataSource`.
|
|
69
|
+
|
|
70
|
+
Packages that write in your transaction (`@nestjs/outbox`, `@nestjs/webhooks`) take the transaction's `EntityManager`, never `dataSource.manager`.
|
|
71
|
+
|
|
72
|
+
## Migrations
|
|
73
|
+
|
|
74
|
+
- Migrations run through TypeORM's CLI, outside the Nest container: no DI in migration classes.
|
|
75
|
+
- Keep a standalone `DataSource` file (e.g. `src/data-source.ts` exporting `new DataSource({...})`) that reads the same env vars, for the CLI to generate and run migrations; set `migrationsRun` or run them in CI/deploy, never `synchronize` in production.
|
|
76
|
+
- Review generated SQL before committing.
|
|
77
|
+
|
|
78
|
+
## Other features
|
|
79
|
+
|
|
80
|
+
- **Subscribers:** `@EventSubscriber()` class implementing `EntitySubscriberInterface<User>`, injecting `DataSource` and calling `dataSource.subscribers.push(this)`; add it to `providers`. Cannot be request-scoped.
|
|
81
|
+
- **EntitySchema:** `new EntitySchema<User>({ name: 'User', target: User, columns, relations })` then `forFeature([UserSchema])`; `name` must equal the target class name.
|
|
82
|
+
- **Multiple databases:** give each non-default data source a `name` (with `forRootAsync`, put `name` beside `useFactory`, not inside); `forFeature([Album], 'albumsConnection')`; `@InjectRepository(Album, 'albumsConnection')`, `@InjectDataSource('albumsConnection')`, `@InjectEntityManager('albumsConnection')`, `getDataSourceToken('albumsConnection')`. Unnamed data sources override each other.
|
|
83
|
+
- **Custom factory:** `dataSourceFactory: async (options) => new DataSource(options!).initialize()` beside `useFactory`.
|
|
84
|
+
|
|
85
|
+
## Testing
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
const moduleRef = await Test.createTestingModule({
|
|
89
|
+
providers: [UsersService, { provide: getRepositoryToken(User), useValue: { findOneBy: vi.fn() } }],
|
|
90
|
+
}).compile();
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
For integration/e2e tests, use a real database (Testcontainers, or SQLite only if queries are portable) with migrations applied, not `synchronize`.
|
|
94
|
+
|
|
95
|
+
## Gotchas
|
|
96
|
+
|
|
97
|
+
- "Nest can't resolve dependencies of UsersService (UserRepository at index [0])": `TypeOrmModule.forFeature([User])` is missing in that module.
|
|
98
|
+
- "No metadata for User was found": entity not registered (`forFeature` or `entities`), or a glob pointing at `.ts` files in `dist`.
|
|
99
|
+
- ESM projects: use `.js` extensions in relative imports and `() => Entity` lazy relation targets to avoid circular import crashes.
|
|
100
|
+
- Load related data explicitly (`relations: { photos: true }`) rather than enabling eager relations everywhere.
|
|
101
|
+
|
|
102
|
+
## Workflow
|
|
103
|
+
|
|
104
|
+
- [ ] 1. Install driver; configure `forRootAsync` from validated config (nestjs-configuration).
|
|
105
|
+
- [ ] 2. Create the entity, `forFeature` it in its module, inject the repository in a service.
|
|
106
|
+
- [ ] 3. Generate and review a migration; apply it locally.
|
|
107
|
+
- [ ] 4. Unit-test services with `getRepositoryToken` mocks; e2e against a real database.
|
|
108
|
+
- [ ] 5. Build, lint, run tests, start the app.
|
|
109
|
+
|
|
110
|
+
Sources: [TypeORM](https://docs.nestjs.com/data/typeorm) · [Database overview](https://docs.nestjs.com/data/overview)
|