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.
Files changed (87) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE.md +6 -0
  4. package/README.md +168 -2
  5. package/bin/nestjs-boost.mjs +148 -0
  6. package/guidelines/core.md +64 -0
  7. package/lib/agents.mjs +137 -0
  8. package/lib/installer.mjs +450 -0
  9. package/lib/prompt.mjs +131 -0
  10. package/lib/setup.mjs +60 -0
  11. package/manifest.json +676 -0
  12. package/package.json +67 -6
  13. package/scripts/postinstall.mjs +49 -0
  14. package/skills/nestjs-ai/SKILL.md +145 -0
  15. package/skills/nestjs-ai/references/ai-reference.md +143 -0
  16. package/skills/nestjs-architecture/SKILL.md +83 -0
  17. package/skills/nestjs-architecture/references/dynamic-modules.md +92 -0
  18. package/skills/nestjs-architecture/references/scopes-lifecycle.md +98 -0
  19. package/skills/nestjs-architecture/references/troubleshooting.md +77 -0
  20. package/skills/nestjs-authentication/SKILL.md +115 -0
  21. package/skills/nestjs-authentication/references/flows.md +180 -0
  22. package/skills/nestjs-authorization/SKILL.md +104 -0
  23. package/skills/nestjs-caching/SKILL.md +109 -0
  24. package/skills/nestjs-cli-tooling/SKILL.md +94 -0
  25. package/skills/nestjs-cli-tooling/references/nest-cli-json.md +91 -0
  26. package/skills/nestjs-configuration/SKILL.md +109 -0
  27. package/skills/nestjs-cqrs/SKILL.md +124 -0
  28. package/skills/nestjs-database-drizzle/SKILL.md +117 -0
  29. package/skills/nestjs-database-mikro-orm/SKILL.md +109 -0
  30. package/skills/nestjs-database-mongoose/SKILL.md +124 -0
  31. package/skills/nestjs-database-prisma/SKILL.md +126 -0
  32. package/skills/nestjs-database-sequelize/SKILL.md +88 -0
  33. package/skills/nestjs-database-typeorm/SKILL.md +110 -0
  34. package/skills/nestjs-deployment/SKILL.md +133 -0
  35. package/skills/nestjs-deployment/references/serverless-and-systemd.md +133 -0
  36. package/skills/nestjs-events/SKILL.md +78 -0
  37. package/skills/nestjs-file-storage/SKILL.md +111 -0
  38. package/skills/nestjs-file-storage/references/storage-reference.md +82 -0
  39. package/skills/nestjs-graphql/SKILL.md +119 -0
  40. package/skills/nestjs-graphql/references/federation.md +110 -0
  41. package/skills/nestjs-graphql/references/schema-features.md +133 -0
  42. package/skills/nestjs-health-checks/SKILL.md +114 -0
  43. package/skills/nestjs-http-client/SKILL.md +118 -0
  44. package/skills/nestjs-http-client/references/http-client-reference.md +116 -0
  45. package/skills/nestjs-http-platform/SKILL.md +104 -0
  46. package/skills/nestjs-http-platform/references/adapters.md +88 -0
  47. package/skills/nestjs-http-web-features/SKILL.md +113 -0
  48. package/skills/nestjs-http-web-features/references/uploads-streaming.md +108 -0
  49. package/skills/nestjs-i18n/SKILL.md +113 -0
  50. package/skills/nestjs-idempotency/SKILL.md +112 -0
  51. package/skills/nestjs-locks/SKILL.md +108 -0
  52. package/skills/nestjs-logging/SKILL.md +123 -0
  53. package/skills/nestjs-mail/SKILL.md +125 -0
  54. package/skills/nestjs-mail/references/mail-reference.md +90 -0
  55. package/skills/nestjs-mcp-server/SKILL.md +152 -0
  56. package/skills/nestjs-mcp-server/references/mcp-reference.md +146 -0
  57. package/skills/nestjs-microservices/SKILL.md +108 -0
  58. package/skills/nestjs-microservices/references/transports.md +117 -0
  59. package/skills/nestjs-observability/SKILL.md +108 -0
  60. package/skills/nestjs-observability/references/apm-and-otel.md +106 -0
  61. package/skills/nestjs-openapi/SKILL.md +90 -0
  62. package/skills/nestjs-openapi/references/swagger-reference.md +180 -0
  63. package/skills/nestjs-outbox/SKILL.md +119 -0
  64. package/skills/nestjs-outbox/references/outbox-reference.md +74 -0
  65. package/skills/nestjs-passport-auth/SKILL.md +125 -0
  66. package/skills/nestjs-queues/SKILL.md +118 -0
  67. package/skills/nestjs-queues/references/bull-legacy.md +75 -0
  68. package/skills/nestjs-request-pipeline/SKILL.md +146 -0
  69. package/skills/nestjs-request-pipeline/references/filters-interceptors.md +114 -0
  70. package/skills/nestjs-request-pipeline/references/pipes-decorators.md +80 -0
  71. package/skills/nestjs-resilience/SKILL.md +116 -0
  72. package/skills/nestjs-resilience/references/resilience-reference.md +74 -0
  73. package/skills/nestjs-scheduling/SKILL.md +100 -0
  74. package/skills/nestjs-security-hardening/SKILL.md +99 -0
  75. package/skills/nestjs-security-hardening/references/throttler-advanced.md +78 -0
  76. package/skills/nestjs-standalone-apps/SKILL.md +78 -0
  77. package/skills/nestjs-testing/SKILL.md +118 -0
  78. package/skills/nestjs-testing/references/advanced-testing.md +62 -0
  79. package/skills/nestjs-upgrading/SKILL.md +82 -0
  80. package/skills/nestjs-upgrading/references/esm-switch.md +114 -0
  81. package/skills/nestjs-validation-serialization/SKILL.md +124 -0
  82. package/skills/nestjs-validation-serialization/references/validation-options.md +84 -0
  83. package/skills/nestjs-webhooks/SKILL.md +116 -0
  84. package/skills/nestjs-webhooks/references/webhooks-reference.md +132 -0
  85. package/skills/nestjs-websockets/SKILL.md +108 -0
  86. package/skills/nestjs-workflows/SKILL.md +123 -0
  87. package/skills/nestjs-workflows/references/workflows-reference.md +85 -0
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: nestjs-caching
3
+ description: Adds caching to NestJS 12 with @nestjs/cache-manager and cache-manager (Keyv) — CacheModule.register/registerAsync, in-memory and Redis (@keyv/redis) or multi-store setups, the CACHE_MANAGER Cache API (get/set/del/clear, TTL in milliseconds), CacheInterceptor auto-caching of GET responses, @CacheKey/@CacheTTL overrides, custom trackBy keys (per user or header), and caching WebSocket and microservice handlers. Use when the user wants to cache responses or query results, add Redis caching, set TTLs, invalidate entries, or debug stale or shared cached responses. Not for HTTP response compression or rate limiting (nestjs-http-platform, nestjs-security-hardening), queues (nestjs-queues) or distributed locks (nestjs-locks).
4
+ compatibility: NestJS 12.x; @nestjs/cache-manager, cache-manager (v7, Keyv-based); optional @keyv/redis, cacheable
5
+ metadata:
6
+ version: "0.1.0"
7
+ nestjs-major: "12"
8
+ docs-crawled: "2026-11-05"
9
+ ---
10
+
11
+ # NestJS caching
12
+
13
+ ```bash
14
+ npm i @nestjs/cache-manager cache-manager
15
+ npm i @keyv/redis cacheable # for Redis + a fast in-memory layer
16
+ ```
17
+
18
+ ## Choose a strategy
19
+
20
+ | Need | Use |
21
+ | --- | --- |
22
+ | Cache an expensive query or external call inside a service | Inject `CACHE_MANAGER`, read-through `get` → compute → `set` (default choice: explicit keys, explicit invalidation) |
23
+ | Cache whole public GET responses | `CacheInterceptor` on the controller or globally |
24
+ | Responses differ per user/tenant | `CacheInterceptor` subclass overriding `trackBy()`, or don't cache at the HTTP layer |
25
+ | Several instances | Redis store (shared); memory-only caches diverge per instance |
26
+
27
+ ## Setup
28
+
29
+ ```typescript
30
+ CacheModule.registerAsync({
31
+ isGlobal: true,
32
+ inject: [ConfigService],
33
+ useFactory: (config: ConfigService) => {
34
+ const redis = createKeyv(config.getOrThrow<string>('REDIS_URL')); // from '@keyv/redis'
35
+ redis.on('error', (err) => logger.error('Redis cache error', err)); // required: unhandled errors crash the app
36
+ return {
37
+ ttl: 60_000, // ms; unset/0 = never expires
38
+ stores: [new Keyv({ store: new KeyvCacheableMemory({ ttl: 60_000, lruSize: 5000 }) }), redis],
39
+ };
40
+ },
41
+ }),
42
+ ```
43
+
44
+ `CacheModule.register()` alone gives an in-memory cache. `isGlobal: true` avoids importing it in each module.
45
+
46
+ ## Service-level caching
47
+
48
+ ```typescript
49
+ constructor(@Inject(CACHE_MANAGER) private readonly cache: Cache, private readonly repo: ProductsRepository) {}
50
+
51
+ async findOne(id: string) {
52
+ const key = `product:${id}`;
53
+ const cached = await this.cache.get<Product>(key);
54
+ if (cached !== undefined && cached !== null) return cached; // v7 returns undefined on miss (v6: null)
55
+ const product = await this.repo.findOne(id);
56
+ await this.cache.set(key, product, 30_000); // TTL in ms; 0 = never expires
57
+ return product;
58
+ }
59
+
60
+ async update(id: string, dto: UpdateProductDto) {
61
+ const product = await this.repo.update(id, dto);
62
+ await this.cache.del(`product:${id}`); // invalidate on write
63
+ return product;
64
+ }
65
+ ```
66
+
67
+ The memory store returns the **same object** you stored: treat cached values as read-only or clone before mutating.
68
+
69
+ ## Response caching with CacheInterceptor
70
+
71
+ ```typescript
72
+ @Controller('catalog')
73
+ @UseInterceptors(CacheInterceptor)
74
+ @CacheTTL(5000)
75
+ export class CatalogController {
76
+ @Get() findAll() { … } // key = request URL
77
+ @CacheKey('catalog_featured') @CacheTTL(2000) @Get('featured') featured() { … }
78
+ }
79
+ ```
80
+
81
+ - Only GET routes are cached (unless a route has an explicit `@CacheKey()`); routes using `@Res()` can't be cached.
82
+ - Global: `{ provide: APP_INTERCEPTOR, useClass: CacheInterceptor }`.
83
+ - The URL key ignores the user: **never** put it on routes whose response depends on who asks (orders, profiles, anything behind record-level authorization). Override `trackBy(context)` to include the user/tenant, or return `undefined` to skip caching.
84
+ - Doesn't work in GraphQL (interceptors run per field resolver).
85
+ - WebSockets/microservices: `@CacheKey('events')` is **required** (and `@CacheTTL` needs it). Don't cache handlers that perform business operations.
86
+
87
+ ```typescript
88
+ @Injectable()
89
+ export class UserAwareCacheInterceptor extends CacheInterceptor {
90
+ trackBy(context: ExecutionContext): string | undefined {
91
+ const req = context.switchToHttp().getRequest();
92
+ if (req.method !== 'GET' || !req.user) return undefined;
93
+ return `${req.user.id}:${req.originalUrl ?? req.url}`;
94
+ }
95
+ }
96
+ ```
97
+
98
+ ## Testing
99
+
100
+ Unit: `{ provide: CACHE_MANAGER, useValue: { get: vi.fn(), set: vi.fn(), del: vi.fn() } }`. Integration: real `CacheModule.register()` (memory) and assert the second call skips the repository.
101
+
102
+ ## Workflow
103
+
104
+ - [ ] 1. Decide service-level vs interceptor caching and the store (Redis for multi-instance).
105
+ - [ ] 2. Register `CacheModule` (global, TTL, Redis `error` listener).
106
+ - [ ] 3. Implement read-through + invalidation, or add the interceptor with per-user `trackBy` where needed.
107
+ - [ ] 4. Test hits, misses and invalidation. Build, lint, run tests, start the app.
108
+
109
+ Sources: [Caching](https://docs.nestjs.com/data/caching)
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: nestjs-cli-tooling
3
+ description: Uses the NestJS 12 CLI and build tooling — nest generate schematics (resource, module, controller, service, guard, …), the CRUD resource generator, converting to a monorepo with apps and libraries (@app/* path aliases), builders (tsc, swc, rspack), SWC with type checking, nest-cli.json options, nest upgrade/nest info/nest deploy, REPL, hot reload and Devtools. Use when scaffolding anything Nest-shaped, adding a second app or shared library, speeding up builds, changing the compiler/bundler, fixing nest-cli.json or path alias issues, or upgrading Nest packages together, even if the user doesn't mention the CLI. Not for runtime module design (nestjs-architecture).
4
+ compatibility: NestJS 12.x; @nestjs/cli 12; generators need Node 22.22.3+, 24.15+ or 26+
5
+ metadata:
6
+ version: "0.1.0"
7
+ nestjs-major: "12"
8
+ docs-crawled: "2026-11-04"
9
+ ---
10
+
11
+ # NestJS CLI and tooling
12
+
13
+ Use the project-local CLI: `npx nest …` (or the package manager's equivalent). Generators place files in Nest's conventional layout, register them in the closest module, and add spec files.
14
+
15
+ ## Generate
16
+
17
+ ```bash
18
+ npx nest g resource orders # prompts for transport (REST/GraphQL/microservice/WS) and CRUD entry points
19
+ npx nest g resource orders --type rest --crud # non-interactive (--crud generates CRUD entry points)
20
+ npx nest g module|controller|service|guard|interceptor|pipe|filter|middleware|decorator|gateway|resolver <name>
21
+ npx nest g service users/admin --flat # no extra folder
22
+ ```
23
+
24
+ | Option | Effect |
25
+ | --- | --- |
26
+ | `--dry-run` / `-d` | Preview the changes |
27
+ | `--no-spec` | Skip spec files (keep them by default) |
28
+ | `--skip-import` | Don't register in the closest module |
29
+ | `--flat` | Don't create a folder |
30
+ | `--project <name>` / `-p` | Target an app or library in a monorepo |
31
+ | `--type rest\|graphql-code-first\|graphql-schema-first\|microservice\|ws` | `resource` only |
32
+
33
+ `nest g resource` creates a module, controller, service, `dto/create-*.dto.ts`, `dto/update-*.dto.ts` (using `PartialType`, adding `@nestjs/mapped-types` if needed), `entities/*.entity.ts` and specs, and imports the module into the app module. It is TypeScript-only. Fill in the generated stubs (DTO fields, service logic) and replace the placeholder "should be defined" specs with real tests.
34
+
35
+ ## Monorepo: apps and libraries
36
+
37
+ ```bash
38
+ npx nest g app worker # first run converts standard mode → monorepo (moves src/ to apps/<name>/)
39
+ npx nest g library common # libs/common, aliased as @app/common in tsconfig paths
40
+ npx nest build worker # build one project; `nest build --all --parallel` builds all
41
+ npx nest start worker --watch
42
+ ```
43
+
44
+ - The conversion moves the existing app to `apps/<original-name>/` and sets `"monorepo": true` and the `projects` map in `nest-cli.json`. Update the `package.json` scripts (`start:prod` → `dist/apps/<name>/main`) and the lint/test globs.
45
+ - **v12 monorepos default to the Rspack builder** (`compilerOptions.builder: "rspack"`), which bundles each app into one file and already compiles with SWC.
46
+ - Import libraries through the alias: `import { CommonModule } from '@app/common'`. The alias lives only in `tsconfig.json` `paths`; **test runners resolve modules themselves**. Mirror the alias in Vitest (`resolve.tsconfigPaths: true` with Vite 8, as generated projects do) or in Jest `moduleNameMapper` for e2e configs.
47
+ - Project-level `compilerOptions` in `nest-cli.json` **replace** the top-level ones; they are not merged.
48
+ - Use `includeLibraryAssets` to copy a library's assets into an app build.
49
+
50
+ ## Faster builds: SWC
51
+
52
+ Standard (non-monorepo) projects:
53
+
54
+ ```bash
55
+ npm i -D @swc/cli @swc/core
56
+ ```
57
+
58
+ ```json
59
+ // nest-cli.json
60
+ { "compilerOptions": { "builder": "swc", "typeCheck": true } }
61
+ ```
62
+
63
+ - `typeCheck: true` runs `tsc --noEmit` alongside SWC, because SWC alone does not type-check.
64
+ - SWC emits ESM when `package.json` has `"type": "module"`, and CommonJS otherwise. A `.swcrc` overrides this; only add one for custom needs.
65
+ - Tests: Vitest needs `unplugin-swc` (the `swc.vite()` plugin) to emit decorator metadata; Jest needs `@swc/jest`.
66
+ - Circular imports under SWC: wrap property and constructor types in `Relation<T>` (TypeORM) or a `WrapperType<T> = T` alias.
67
+
68
+ ## Upgrading and diagnostics
69
+
70
+ - `nest upgrade` (from the project root, after updating the global CLI): moves all `@nestjs/*` packages to the matching major at once, bumps TypeScript to v6, migrates `nest-cli.json` webpack options to Rspack, and prints a report. Run it with `--dry-run` first. It deliberately doesn't switch you to ESM, Vitest or oxlint.
71
+ - `nest info`: prints Node, CLI and `@nestjs/*` versions. Include it in bug reports.
72
+ - `nest add <lib>`: installs a library and runs its schematic.
73
+ - `nest deploy`: forwards to NestJS Mau (installs `@nestjs/mau` on first use).
74
+
75
+ ## Gotchas
76
+
77
+ - **webpack is deprecated** in v12: `--webpack`, `--webpackPath` and `webpack`/`webpackConfigPath` in `nest-cli.json` → use `--builder rspack` (or `swc`/`tsc`). The hot-reload recipe still targets webpack-based CommonJS projects.
78
+ - **Generators need a newer Node** (22.22.3+, 24.15+ or 26+) than running the app (20.19+).
79
+ - `nest g decorator` generates the `Reflector.createDecorator()` form in v12.
80
+ - Run the generator from the project root; inside a monorepo, pass `--project`.
81
+ - Converting to a monorepo only works for the canonical Nest structure (`src/` + `test/` at the root); the schematic moves both folders into `apps/<name>/`.
82
+
83
+ ## Workflow
84
+
85
+ - [ ] 1. Preview with `--dry-run`, then generate.
86
+ - [ ] 2. Check the module registration and imports the generator added; fill in the generated stubs.
87
+ - [ ] 3. After structural changes (monorepo, builder), update `package.json` scripts and test-runner aliases.
88
+ - [ ] 4. Build every affected project, run lint and both test suites, and start the built app.
89
+
90
+ ## Reference files
91
+
92
+ - `references/nest-cli-json.md`: every `nest-cli.json` property (compilerOptions, generateOptions, assets, projects), REPL, hot reload, Devtools and CI integration. Read when editing `nest-cli.json` or setting up these tools.
93
+
94
+ Sources: [CLI usage](https://docs.nestjs.com/cli/usages) · [Workspaces](https://docs.nestjs.com/cli/monorepo) · [Libraries](https://docs.nestjs.com/cli/libraries) · [CRUD generator](https://docs.nestjs.com/recipes/crud-generator) · [SWC](https://docs.nestjs.com/recipes/swc) · [Migration guide](https://docs.nestjs.com/migration-guide)
@@ -0,0 +1,91 @@
1
+ # nest-cli.json, REPL, hot reload and Devtools
2
+
3
+ Sources: [Workspaces](https://docs.nestjs.com/cli/monorepo) · [CLI usage](https://docs.nestjs.com/cli/usages) · [REPL](https://docs.nestjs.com/recipes/repl) · [Hot reload](https://docs.nestjs.com/recipes/hot-reload) · [Devtools](https://docs.nestjs.com/devtools/overview) · [CI/CD integration](https://docs.nestjs.com/devtools/ci-cd-integration)
4
+
5
+ ## Contents
6
+ - compilerOptions
7
+ - generateOptions
8
+ - Assets
9
+ - Monorepo project entries
10
+ - REPL
11
+ - Hot reload
12
+ - Devtools
13
+
14
+ ## compilerOptions
15
+
16
+ | Property | Type | Notes |
17
+ | --- | --- | --- |
18
+ | `builder` | `"tsc" \| "swc" \| "rspack"` or `{ type, options }` | Monorepos default to `rspack` in v12 |
19
+ | `typeCheck` | boolean | With `swc`: run type checking alongside (default `false`) |
20
+ | `emitDeclarations` | boolean | Emit `.d.ts` with SWC |
21
+ | `deleteOutDir` | boolean | Clean `dist` before each build |
22
+ | `assets` | array | Copy non-TS files (not on incremental watch compiles) |
23
+ | `watchAssets` | boolean | Watch all non-TS assets |
24
+ | `manualRestart` | boolean | Enable the `rs` shortcut to restart |
25
+ | `tsConfigPath` | string | Monorepo: tsconfig used when no project is given |
26
+ | `includeLibraryAssets` | array | Monorepo: library projects whose assets are copied into this app |
27
+ | `webpack`, `webpackConfigPath` | — | **Deprecated** in v12; use `builder` (`builder.options.configPath`) |
28
+
29
+ Builder object form: `{ "builder": { "type": "swc", "options": { "swcrcPath": "infrastructure/.swcrc" } } }`.
30
+
31
+ ## generateOptions
32
+
33
+ ```json
34
+ { "generateOptions": { "spec": false, "flat": true } }
35
+ ```
36
+
37
+ `spec` can also be an object per schematic, e.g. `{ "service": true, "controller": false }`. Command-line flags override it, and project-level `generateOptions` override the top-level ones.
38
+
39
+ ## Assets
40
+
41
+ ```json
42
+ { "compilerOptions": { "assets": ["**/*.graphql", { "include": "i18n/**/*", "outDir": "dist/i18n", "watchAssets": true }] } }
43
+ ```
44
+
45
+ ## Monorepo project entries
46
+
47
+ ```json
48
+ {
49
+ "monorepo": true,
50
+ "root": "apps/api",
51
+ "sourceRoot": "apps/api/src",
52
+ "compilerOptions": { "builder": "rspack", "tsConfigPath": "apps/api/tsconfig.app.json" },
53
+ "projects": {
54
+ "api": { "type": "application", "root": "apps/api", "entryFile": "main", "sourceRoot": "apps/api/src", "compilerOptions": { "tsConfigPath": "apps/api/tsconfig.app.json" } },
55
+ "common": { "type": "library", "root": "libs/common", "entryFile": "index", "sourceRoot": "libs/common/src", "compilerOptions": { "tsConfigPath": "libs/common/tsconfig.lib.json" } }
56
+ }
57
+ }
58
+ ```
59
+
60
+ A project's `compilerOptions` replace the top-level ones; they are not merged.
61
+
62
+ ## REPL
63
+
64
+ ```typescript
65
+ // src/repl.ts
66
+ import { repl } from '@nestjs/core';
67
+ import { AppModule } from './app.module.js';
68
+ await repl(AppModule);
69
+ ```
70
+
71
+ Run it with `npm run start -- --entryFile repl`. Inside: `get(UsersService)` (alias `$`), `await $(UsersService).findAll()`, `debug()`, `methods(UsersService)`, `resolve()`, `select()`.
72
+
73
+ ## Hot reload
74
+
75
+ The documented recipe targets **webpack-based CommonJS** projects (webpack is deprecated in v12, and Rspack is the monorepo default). For ESM or SWC projects, `nest start --watch` with the SWC builder is usually fast enough. Use the recipe only if the project still uses webpack.
76
+
77
+ ## Devtools
78
+
79
+ ```typescript
80
+ const app = await NestFactory.create(AppModule, { snapshot: true }); // main.ts
81
+ ```
82
+
83
+ ```bash
84
+ npm i @nestjs/devtools-integration
85
+ ```
86
+
87
+ ```typescript
88
+ @Module({ imports: [DevtoolsModule.register({ http: process.env.NODE_ENV !== 'production' })] })
89
+ ```
90
+
91
+ Devtools offers a graph explorer, routes explorer, playground, bootstrap performance analyzer, audit, and help with "Cannot resolve dependency" errors. CI/CD integration publishes graph snapshots for pull requests (see the CI/CD integration page).
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: nestjs-configuration
3
+ description: Configures NestJS 12 applications with @nestjs/config — loading .env files and environment variables, fail-fast validation with a Standard Schema (Zod/Valibot/ArkType) validationSchema or validate() function, typed namespaced config with registerAs/ConfigType, global ConfigModule, reading config in main.ts and in async module factories (forRootAsync), env-specific files and variable expansion. Use when the user wants settings from env/.env, required variables, typed config, per-environment config, configuring another module from config, or when ConfigService is undefined, a variable is missing at startup, or Joi validation options stopped working after upgrading. Not for request validation (nestjs-validation-serialization).
4
+ compatibility: NestJS 12.x; @nestjs/config; zod (or valibot/arktype) for validation
5
+ metadata:
6
+ version: "0.1.0"
7
+ nestjs-major: "12"
8
+ docs-crawled: "2026-11-04"
9
+ ---
10
+
11
+ # NestJS configuration
12
+
13
+ ## Default recipe
14
+
15
+ ```bash
16
+ npm i @nestjs/config zod
17
+ ```
18
+
19
+ ```typescript
20
+ // config/env.schema.ts
21
+ import { z } from 'zod';
22
+ export const envSchema = z.object({
23
+ NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
24
+ PORT: z.coerce.number().int().default(3000), // env values are strings: coerce
25
+ DATABASE_URL: z.url(), // no default → required: startup fails if missing
26
+ });
27
+ export type Env = z.infer<typeof envSchema>;
28
+ ```
29
+
30
+ ```typescript
31
+ // app.module.ts
32
+ @Module({
33
+ imports: [
34
+ ConfigModule.forRoot({
35
+ isGlobal: true, // inject ConfigService anywhere without importing ConfigModule
36
+ validationSchema: envSchema, // any Standard Schema; ConfigService serves the schema's OUTPUT (coerced, defaulted)
37
+ load: [databaseConfig], // namespaced, typed config (below)
38
+ }),
39
+ ],
40
+ })
41
+ export class AppModule {}
42
+ ```
43
+
44
+ ```typescript
45
+ // main.ts
46
+ const app = await NestFactory.create(AppModule);
47
+ const config = app.get(ConfigService);
48
+ await app.listen(config.getOrThrow<number>('PORT'));
49
+ ```
50
+
51
+ Validation runs during bootstrap. Unknown variables (`PATH`, `HOME`) are ignored, and every failing variable is reported as `NAME: message`. In v12, Zod (or another Standard Schema library) is the recommended choice for new code ([Configuration](https://docs.nestjs.com/application/configuration)).
52
+
53
+ ## Typed, namespaced config (preferred over string keys)
54
+
55
+ ```typescript
56
+ // config/database.config.ts
57
+ export const databaseConfig = registerAs('database', () => ({
58
+ host: process.env.DB_HOST ?? 'localhost',
59
+ port: Number(process.env.DB_PORT ?? 5432),
60
+ }));
61
+
62
+ // any provider
63
+ constructor(@Inject(databaseConfig.KEY) private readonly db: ConfigType<typeof databaseConfig>) {}
64
+ this.db.port; // number, fully typed
65
+
66
+ // configure another module from it
67
+ TypeOrmModule.forRootAsync(databaseConfig.asProvider())
68
+ ```
69
+
70
+ - `ConfigModule.forFeature(databaseConfig)` registers a namespace from a feature module (partial registration). Values loaded this way may only be ready in `onModuleInit()`, not the constructor.
71
+ - `configService.get('database.host')` also works; prefer `.KEY` injection for types.
72
+ - In `registerAs` factories, `process.env` is fully resolved (`.env` merged) and has already passed validation.
73
+
74
+ ## Reading values
75
+
76
+ | Need | Use |
77
+ | --- | --- |
78
+ | Optional value with fallback | `config.get<string>('FEATURE_GREETING', 'Hello')` |
79
+ | Required value | `config.getOrThrow<string>('API_KEY')`: throws if undefined |
80
+ | Typed keys from a schema | `ConfigService<Env, true>` + `get('PORT', { infer: true })` |
81
+ | Another module's async config | `forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (c: ConfigService) => ({ ... }) })`. Omit `imports` when `isGlobal: true`. |
82
+
83
+ ## Decision points
84
+
85
+ - **Several env files** → `envFilePath: ['.env.development.local', '.env.development']` (the first match wins per key). `ignoreEnvFile: true` uses `process.env` only, e.g. with `node --env-file=.env`.
86
+ - **`${VAR}` references in `.env`** → `expandVariables: true`.
87
+ - **Load a module only when an env flag is set** → `ConditionalModule.registerWhen(FooModule, 'USE_FOO')`.
88
+ - **Env needed before `AppModule` is imported** (e.g. microservice options in `createMicroservice()`) → `nest start --env-file .env`, or `process.loadEnvFile()` in a file imported first in `main.ts`.
89
+ - **Hot paths reading config often** → `cache: true`.
90
+ - **Custom rules beyond a schema** → a **synchronous** `validate: (raw) => parsed`: return the validated object, or throw.
91
+
92
+ ## Gotchas
93
+
94
+ - **Joi in v12** needs **Joi v18+**, and Joi settings (`allowUnknown`, `abortEarly`) move under `validationOptions.libraryOptions`. Top-level `validationOptions.allowUnknown` no longer applies. For new code, use Zod.
95
+ - **`ConfigService` undefined or not found in a feature module:** `ConfigModule` isn't global and isn't imported there. Set `isGlobal: true` once in `AppModule`.
96
+ - **Env values are strings:** a schema without `z.coerce.number()` rejects `PORT=3000`, and a manual `process.env.PORT` read gives a string. Rely on the schema output via `ConfigService`.
97
+ - **Tests and required vars:** e2e tests importing `AppModule` fail validation without the required variables. Provide test values in the test runner config (e.g. `test.env` in `vitest.config.e2e.ts`) or a `.env.test` file via `envFilePath`. Never weaken the schema for tests.
98
+ - **Never commit `.env`** with real secrets. Commit `.env.example` and add `.env` to `.gitignore`.
99
+ - **`process.loadEnvFile()` inside `main.ts`'s body runs too late**, because `forRoot()` already read `process.env` when `app.module` was imported. Node's native `.env` parser isn't fully dotenv-compatible.
100
+
101
+ ## Workflow
102
+
103
+ - [ ] 1. `npm i @nestjs/config zod` (skip zod if the project already uses another Standard Schema library).
104
+ - [ ] 2. Write the env schema; mark required variables by leaving out defaults.
105
+ - [ ] 3. `ConfigModule.forRoot({ isGlobal: true, validationSchema })` in `AppModule`; add `registerAs` namespaces for grouped settings.
106
+ - [ ] 4. Read `PORT` etc. in `main.ts` with `app.get(ConfigService)`.
107
+ - [ ] 5. Add `.env.example`, make tests supply required variables, and run build, lint and tests. Start the app once **with and without** a required variable to confirm fail-fast.
108
+
109
+ Sources: [Configuration](https://docs.nestjs.com/application/configuration) · [Migration guide](https://docs.nestjs.com/migration-guide)
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: nestjs-cqrs
3
+ description: Implements CQRS in NestJS 12 with @nestjs/cqrs — CqrsModule.forRoot options and custom publishers, typed Command/Query classes with CommandBus/QueryBus execute, @CommandHandler/@QueryHandler/@EventsHandler providers, AggregateRoot apply/commit with EventPublisher.mergeObjectContext, WithAggregateRoot mixin and IAggregateRoot, passing a transaction as dispatcher context to commit/publish (12.1+), RxJS @Saga with ofType, durable sagas via @nestjs/workflows/cqrs (@StartOn, @SignalOn), the UnhandledExceptionBus, subscribing to all events, and request-scoped handlers with AsyncContext. Use when the user asks for CQRS, commands and queries, domain events from aggregates, sagas, event sourcing foundations, or when event handler errors disappear or saga commands are lost on restart. Not for simple in-process notifications (nestjs-events), durable delivery to other services (nestjs-outbox) or long-running processes on their own (nestjs-workflows).
4
+ compatibility: NestJS 12.x; @nestjs/cqrs (12.1+ for awaited commit/dispatcher context); @nestjs/workflows for durable sagas
5
+ metadata:
6
+ version: "0.1.0"
7
+ nestjs-major: "12"
8
+ docs-crawled: "2026-11-05"
9
+ ---
10
+
11
+ # NestJS CQRS (@nestjs/cqrs)
12
+
13
+ Use CQRS where separate read/write models or domain events pay off; for plain CRUD, services are simpler. Follow the project's existing structure (e.g. `orders/commands`, `orders/queries`, `orders/events`, `orders/sagas`).
14
+
15
+ ```bash
16
+ npm i @nestjs/cqrs
17
+ ```
18
+
19
+ ```typescript
20
+ @Module({ imports: [CqrsModule.forRoot()] }) // options: commandPublisher, eventPublisher, queryPublisher, unhandledExceptionPublisher, eventIdProvider, rethrowUnhandled
21
+ export class AppModule {}
22
+ ```
23
+
24
+ ## Commands and queries
25
+
26
+ ```typescript
27
+ export class PlaceOrderCommand extends Command<{ orderId: string }> { // generic = typed result
28
+ constructor(readonly customerId: string, readonly items: OrderItem[]) { super(); }
29
+ }
30
+
31
+ @CommandHandler(PlaceOrderCommand)
32
+ export class PlaceOrderHandler implements ICommandHandler<PlaceOrderCommand> {
33
+ constructor(private readonly repo: OrdersRepository, private readonly publisher: EventPublisher) {}
34
+ async execute({ customerId, items }: PlaceOrderCommand) {
35
+ const order = this.publisher.mergeObjectContext(Order.place(customerId, items)); // aggregate can publish
36
+ await this.repo.save(order);
37
+ order.commit(); // dispatch applied events
38
+ return { orderId: order.id };
39
+ }
40
+ }
41
+
42
+ export class GetOrderQuery extends Query<OrderView> { constructor(readonly id: string) { super(); } }
43
+ @QueryHandler(GetOrderQuery)
44
+ export class GetOrderHandler implements IQueryHandler<GetOrderQuery> {
45
+ constructor(private readonly views: OrderViewsRepository) {}
46
+ execute({ id }: GetOrderQuery) { return this.views.find(id); }
47
+ }
48
+
49
+ // controller
50
+ const { orderId } = await this.commandBus.execute(new PlaceOrderCommand(user.id, dto.items));
51
+ const order = await this.queryBus.execute(new GetOrderQuery(id)); // typed as OrderView
52
+ ```
53
+
54
+ - Register every handler, event handler and saga class in `providers`.
55
+ - Command handler errors reach exception filters; return values go back to the caller.
56
+ - One handler per command/query; many handlers per event.
57
+
58
+ ## Aggregates and events
59
+
60
+ ```typescript
61
+ export class Order extends AggregateRoot {
62
+ static place(customerId: string, items: OrderItem[]) {
63
+ const order = new Order(randomUUID(), customerId, items);
64
+ order.apply(new OrderPlacedEvent(order.id, customerId)); // queued until commit()
65
+ return order;
66
+ }
67
+ }
68
+
69
+ @EventsHandler(OrderPlacedEvent)
70
+ export class OrderPlacedHandler implements IEventHandler<OrderPlacedEvent> {
71
+ async handle(event: OrderPlacedEvent) { try { … } catch (e) { this.logger.error(…); } }
72
+ }
73
+ ```
74
+
75
+ - `autoCommit = true` publishes on `apply()`. `mergeClassContext(Order)` merges into a class. Existing base classes: `class Dragon extends WithAggregateRoot(Monster)`; framework-free domain: implement `IAggregateRoot`.
76
+ - Direct publishing: `eventBus.publish(event)` / `publishAll`.
77
+ - **Event handlers run outside the request**: exception filters don't see their errors and they can't write HTTP responses. Handle errors inside, or subscribe to `UnhandledExceptionBus` (`UnhandledExceptionBus.ofType(X)`); `rethrowUnhandled: true` rethrows instead.
78
+ - 12.1+: `commit()`/`publish()` return what the publisher returns and accept a dispatcher context: `await order.commit({ transaction: tx })` — for publishers that write through the transaction (outbox, workflows). `commit()` clears events immediately; on failure roll back and re-run the command with a fresh aggregate.
79
+ - The default event bus is in-memory: events are lost on crash. For cross-service or must-happen reactions, publish through the outbox (nestjs-outbox).
80
+
81
+ ## Sagas
82
+
83
+ ```typescript
84
+ @Injectable()
85
+ export class OrderSagas {
86
+ @Saga()
87
+ orderPlaced = (events$: Observable<any>): Observable<ICommand> =>
88
+ events$.pipe(ofType(OrderPlacedEvent), map((e) => new ReserveStockCommand(e.orderId)));
89
+ }
90
+ ```
91
+
92
+ Sagas are in-memory singletons. For processes that must survive restarts (wait for payment, timeouts), use a durable workflow:
93
+
94
+ ```typescript
95
+ @Module({ imports: [CqrsModule.forRoot(), WorkflowsModule.forRoot(), WorkflowsCqrsModule], providers: [PlaceOrderHandler, OrderFulfilmentWorkflow] })
96
+
97
+ @Workflow('order-fulfilment')
98
+ @StartOn(OrderPlacedEvent, { id: (e) => `order-${e.order.id}`, input: (e) => e.order })
99
+ @SignalOn(OrderDeliveredEvent, { signal: shipmentDelivered, key: (e) => e.delivery.reference })
100
+ export class OrderFulfilmentWorkflow implements WorkflowRunner<Order, FulfilmentResult> { … }
101
+
102
+ // in the command handler's transaction, so the workflow exists iff the order does
103
+ await this.eventBus.publish(new OrderPlacedEvent(order), { transaction: tx });
104
+ ```
105
+
106
+ See nestjs-workflows for steps, signals and stores.
107
+
108
+ ## Request scope
109
+
110
+ Handlers can be `@CommandHandler(X, { scope: Scope.REQUEST })`. Pass context explicitly: `commandBus.execute(cmd, new MyRequest(user))` where `MyRequest extends AsyncContext`, inject with `@Inject(REQUEST)`. Sagas stay singletons: carry context with `AsyncContext.of(event)` + `AsyncContext.merge(ctx, command)`.
111
+
112
+ ## Testing
113
+
114
+ Unit-test handlers by instantiating them with fake repositories and `{ mergeObjectContext: (o) => o }` as publisher; assert `aggregate.getUncommittedEvents()`. Test sagas by feeding `of(new OrderPlacedEvent(…))` into the saga function and collecting emitted commands.
115
+
116
+ ## Workflow
117
+
118
+ - [ ] 1. Install; `CqrsModule.forRoot()`.
119
+ - [ ] 2. Command/query classes with typed results; handlers registered as providers.
120
+ - [ ] 3. Aggregates apply events; command handlers merge context and commit after persisting (with the transaction as context when needed).
121
+ - [ ] 4. Event handlers with their own error handling; `UnhandledExceptionBus` subscriber; durable workflows instead of sagas for must-survive processes.
122
+ - [ ] 5. Tests. Build, lint, run tests, start the app.
123
+
124
+ Sources: [CQRS](https://docs.nestjs.com/recipes/cqrs)
@@ -0,0 +1,117 @@
1
+ ---
2
+ name: nestjs-database-drizzle
3
+ description: Integrates Drizzle ORM with NestJS 12 through the first-party @nestjs/drizzle package — DrizzleModule.forRoot/forRootAsync with a driver's drizzle() function, per-application connection pools closed on shutdown, @InjectDrizzle and getDrizzleToken, pgTable/mysqlTable schemas with $inferSelect types, defineRelations and typed db.query relational reads, transactions with db.transaction(tx), hand-written repositories, drizzle-kit migrations or migrate() at startup, read replicas with withReplicas, multiple named databases, and mocking the database in tests. Use when the project uses or wants Drizzle (PostgreSQL, MySQL, SQLite, Neon, Turso, D1), when adding a table, query, relation, transaction or migration with Drizzle, or when e2e tests break because a shared db instance was closed. Not for TypeORM, Prisma, Mongoose, MikroORM or Sequelize (their own skills).
4
+ compatibility: NestJS 12.x; @nestjs/drizzle; drizzle-orm v1 (rc) or ≥0.35; drizzle-kit
5
+ metadata:
6
+ version: "0.1.0"
7
+ nestjs-major: "12"
8
+ docs-crawled: "2026-11-05"
9
+ ---
10
+
11
+ # NestJS + Drizzle (@nestjs/drizzle)
12
+
13
+ ```bash
14
+ npm i @nestjs/drizzle drizzle-orm@rc pg
15
+ npm i -D drizzle-kit@rc @types/pg
16
+ ```
17
+
18
+ The docs target Drizzle v1 (`rc` tag). With v0.x (≥0.35), only relations and relational queries differ. Detect the installed version before writing relations.
19
+
20
+ ## Schema and types
21
+
22
+ ```typescript
23
+ // src/db/schema.ts
24
+ export const users = pgTable('users', {
25
+ id: integer().primaryKey().generatedAlwaysAsIdentity(),
26
+ email: text().notNull().unique(),
27
+ isActive: boolean('is_active').notNull().default(true),
28
+ });
29
+ export const photos = pgTable('photos', {
30
+ id: integer().primaryKey().generatedAlwaysAsIdentity(),
31
+ userId: integer('user_id').notNull().references(() => users.id), // FK constraint
32
+ });
33
+ export type User = typeof users.$inferSelect;
34
+ export type NewUser = typeof users.$inferInsert;
35
+
36
+ // src/db/relations.ts — drives db.query only (v1 API)
37
+ export const relations = defineRelations(schema, (r) => ({
38
+ users: { photos: r.many.photos() },
39
+ photos: { user: r.one.users({ from: r.photos.userId, to: r.users.id }) },
40
+ }));
41
+
42
+ // src/db/database.ts
43
+ export type Database = NodePgDatabase<typeof relations>;
44
+ ```
45
+
46
+ No entity classes and no `forFeature()`: tables are plain objects you import where you query.
47
+
48
+ ## Register (once, globally injectable)
49
+
50
+ ```typescript
51
+ DrizzleModule.forRootAsync({
52
+ inject: [ConfigService],
53
+ useFactory: (config: ConfigService) => ({
54
+ drizzle, // from 'drizzle-orm/node-postgres'
55
+ connection: config.getOrThrow<string>('DATABASE_URL'),
56
+ relations, // other drizzle() options (logger, casing) pass through
57
+ }),
58
+ }),
59
+ ```
60
+
61
+ - `DrizzleModule` creates the client **per application instance** and closes `db.$client` on `app.close()` / shutdown signal (`autoCloseConnection: true`). Enable `app.enableShutdownHooks()`.
62
+ - `forRoot()` options are evaluated at import time; prefer `forRootAsync` with `ConfigService`.
63
+ - Bring your own instance (replicas): `useFactory: () => ({ db: withReplicas(drizzle(primaryUrl), [drizzle(replicaUrl)]) })`. Avoid passing a module-level `db` singleton to `forRoot()`: every app shares it and the first `app.close()` breaks the other e2e suites.
64
+
65
+ ## Queries, transactions, repositories
66
+
67
+ ```typescript
68
+ @Injectable()
69
+ export class UsersService {
70
+ constructor(@InjectDrizzle() private readonly db: Database) {}
71
+
72
+ async findOne(id: number) { const [u] = await this.db.select().from(users).where(eq(users.id, id)); return u; }
73
+ findWithPhotos(id: number) { return this.db.query.users.findFirst({ where: { id }, with: { photos: true } }); }
74
+ async create(data: NewUser) { const [u] = await this.db.insert(users).values(data).returning(); return u; }
75
+
76
+ async deactivate(id: number) {
77
+ await this.db.transaction(async (tx) => { // every statement through tx
78
+ await tx.update(users).set({ isActive: false }).where(eq(users.id, id));
79
+ await tx.delete(photos).where(eq(photos.userId, id));
80
+ });
81
+ }
82
+ }
83
+ ```
84
+
85
+ - A query runs when awaited. A thrown error or `tx.rollback()` rolls back.
86
+ - Optional repository layer: an `@Injectable()` class with named query methods; it uses the injected db, so **it is not part of a transaction started elsewhere** — accept `tx` as a parameter or propagate it with `nestjs-cls` transactional + Drizzle adapter (nestjs-logging covers CLS).
87
+ - `@nestjs/outbox`, `@nestjs/webhooks` and `@nestjs/authentication` stores use `fromDrizzle(db)` and take your `tx`.
88
+
89
+ ## Migrations
90
+
91
+ ```typescript
92
+ // drizzle.config.ts
93
+ export default defineConfig({ dialect: 'postgresql', schema: './src/db/schema.ts', out: './drizzle', dbCredentials: { url: process.env.DATABASE_URL! } });
94
+ ```
95
+
96
+ - `npx drizzle-kit generate` → SQL files; `npx drizzle-kit migrate` applies them. Drizzle Kit runs outside Nest (no DI) and loads `.env` itself.
97
+ - Migrate at startup only for single-instance deployments: `useFactory: async () => { const db = drizzle(url, { relations }); await migrate(db, { migrationsFolder: './drizzle' }); return { db }; }`. With several instances, run `drizzle-kit migrate` as a release step.
98
+ - Custom SQL (e.g. other packages' store schemas): `npx drizzle-kit generate --custom --name=<name>`.
99
+
100
+ ## Multiple databases
101
+
102
+ `DrizzleModule.forRoot({ name: 'analytics', drizzle, connection })` per extra database (one may stay unnamed = `default`); inject with `@InjectDrizzle('analytics')` or `getDrizzleToken('analytics')`. Drivers can differ.
103
+
104
+ ## Testing
105
+
106
+ - Unit: `{ provide: getDrizzleToken(), useValue: mockDb }` — the chain (`select().from().where()`) must be mocked, so prefer mocking your repository class.
107
+ - Integration/e2e: override `getDrizzleToken()` with a PGlite database (`drizzle({ client: new PGlite() })` from `drizzle-orm/pglite`) after running `migrate(db, { migrationsFolder })` — in-process PostgreSQL, no server.
108
+
109
+ ## Workflow
110
+
111
+ - [ ] 1. Install driver + `@nestjs/drizzle` + drizzle-kit; write `schema.ts` (+ `relations.ts`, `Database` type).
112
+ - [ ] 2. Register `DrizzleModule.forRootAsync`; enable shutdown hooks.
113
+ - [ ] 3. Inject with `@InjectDrizzle()`; wrap multi-statement writes in `db.transaction`.
114
+ - [ ] 4. `drizzle-kit generate`, review SQL, `drizzle-kit migrate`.
115
+ - [ ] 5. Tests (repository mocks; PGlite e2e). Build, lint, run tests, start the app.
116
+
117
+ Sources: [Drizzle](https://docs.nestjs.com/data/drizzle)