nestjs-architecture
Skill0 starsChanged 16 days agoMITView on GitHub
Use when creating, moving, or naming files in a NestJS backend organized as feature modules (modules/) with shared infrastructure (infra/) and framework plumbing (common/). Covers module layout, naming, DI boundaries, placement of pipes, guards, middleware, filters, and interceptors, config, GraphQL, CQRS, queues, websockets, tests, and growth from prototype to monorepo.
- Reads credentials
1 other project uses a version of this.
Adopted by
Most recently taken up by
- bryanus1/agent-skillstheir own version, first seen Nov 1, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- bryanus1/agent-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository7 other files it gives its agents.
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. About 0 are common, 10 are distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈10
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 17
Read src/ before creating files.
- Distinctive: line 50
Read references/full-tree.md when you need the expanded tree.
- Distinctive: line 52
Add a folder on first use.
- Distinctive: line 79
Read references/request-lifecycle.md when adding or placing middleware, guards, interceptors, pipes, filters, or custom decorators.
- Distinctive: line 86
Read the matching reference before adding the first file of each kind:
- Distinctive: line 105
Test services, policies, and pipes directly without HTTP.
- Distinctive: line 109
Read references/growth-stages.md when deciding whether to restructure.
- Distinctive: line 127
Read references/anti-patterns.md when reviewing a layout or before moving files.
- Distinctive: line 129
Do not put business logic in controllers, resolvers, or gateways.
- Distinctive: line 130
Do not inject another module's repository or entity.
- Very specific: line 131
Do not use forwardRef as a routine fix.
- Very specific: line 132
Do not mark modules @Global() by default.
- Very specific: line 133
Do not put a single-module guard, filter, or interceptor in common/.
- Very specific: line 134
Do not read process.env outside *.config.ts files.
- Distinctive: line 135
Do not return entities from controllers.
- Very specific: line 136
Do not create utils/, helpers/, or a providerless SharedModule dumping ground.
- Very specific: line 137
Do not register the same pipe globally in both main.ts and APP_PIPE.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
NestJS architecture
Server-side NestJS app organized by feature module. Business features live in modules/, cross-cutting technical capabilities in infra/, reusable framework plumbing in common/. One app can serve REST, GraphQL, WebSockets, and background workers from this layout.
Target version
Written for NestJS 11 and 12 (TypeScript, Express adapter by default) on 2026-11-02. v12 changes packaging (ESM) and adds Standard Schema DTO validation; it does not change layout.
Follow the repo first
Read src/ before creating files. Check nest-cli.json for sourceRoot and monorepo mode, app.module.ts for how modules are registered, and existing file suffixes. If the project keeps modules directly under src/, follow that until the move described in growth stages.
Default directory layout
src/
main.ts # bootstrap only: create app, adapter setup, listen
app.module.ts # root module: ConfigModule + infra + feature modules
common/ # framework plumbing used by 2+ modules, no business logic
decorators/ # param and metadata decorators (CurrentUser, Public)
errors/ # shared HttpException subclasses
filters/ # exception filters (all-exceptions, query-failed)
guards/ # guards used across modules
interceptors/ # logging, serialization, response envelope
middleware/ # request-id, request logging
pipes/ # custom validation and transform pipes
infra/ # technical capability modules, one folder per concern
database/ # ORM module + database.config.ts
queue/ # BullMQ connection, queue names
mailer/ # mail module, queue + processor, mails/, templates/
redis/ storage/ rate-limit/
modules/ # feature modules, one folder per business capability
users/
users.module.ts
users.controller.ts
users.service.ts
users.repository.ts
user.entity.ts
user.dto.ts
i18n/ # translation catalogs, one folder per locale
test/ # e2e specs only; unit tests are colocatedRead references/full-tree.md when you need the expanded tree.
- Add a folder on first use. Do not create empty ones.
- A guard, filter, pipe, or interceptor used by one module lives in that module, not in
common/. - A large feature nests submodules:
modules/auth/{password,mfa,oidc}/, each with its own*.module.ts.
Naming conventions
- Files and folders: kebab-case with a role suffix:
users.controller.ts,users.service.ts,users.repository.ts,users.module.ts. - Plural for module, controller, service, repository; singular for data shapes:
user.entity.ts,user.dto.ts,user.types.ts. - One suffix per Nest concept:
.guard.ts,.pipe.ts,.filter.ts,.interceptor.ts,.middleware.ts,.decorator.ts,.exception.ts,.gateway.ts,.resolver.ts,.processor.ts,.listener.ts,.event.ts,.config.ts. - Classes: PascalCase with the suffix spelled out:
UsersController,CreateUserDto,AllExceptionsFilter,JwtAuthGuard. - DTOs: one
user.dto.tsper resource exportingCreateUserDto,UpdateUserDto; split per use case only when the file passes ~5 DTOs. - Tests:
users.service.spec.tsnext to the file. E2e:test/users.e2e-spec.ts.
Dependency direction
modules -> infra -> common- A module reaches another module only through
@Moduleimports and exported providers. Never import another module's repository, entity, or internal service directly. - Inside a module: controller -> service -> repository. Controllers hold no business logic; repositories hold no business rules.
common/imports nothing frommodules/orinfra/.- Export from a module only what other modules need. Everything else stays private.
- A circular dependency between two modules means a concept is missing. Extract a third module instead of reaching for
forwardRef.
Request lifecycle plumbing
Read references/request-lifecycle.md when adding or placing middleware, guards, interceptors, pipes, filters, or custom decorators.
- Execution order: middleware -> guards -> interceptors (pre) -> pipes -> handler -> interceptors (post) -> filters.
- Bind global plumbing with
APP_PIPE,APP_GUARD,APP_FILTER,APP_INTERCEPTORproviders inapp.module.tsso it gets DI. Useapp.useGlobal*inmain.tsonly when nothing needs injection.
Beyond REST
Read the matching reference before adding the first file of each kind:
- references/graphql.md: resolvers, object types, inputs, dataloaders (code-first).
- references/cqrs.md:
commands/,queries/,events/,sagas/inside a module with@nestjs/cqrs. - references/queues-and-events.md: BullMQ queues and processors, event emitter listeners,
@nestjs/schedulecron jobs. - references/websockets.md: gateways, adapters, event name constants.
Where things live
- Config:
<name>.config.tscolocated with its module usingregisterAs(database.config.tsininfra/database/,auth.config.tsinmodules/auth/).ConfigModule.forRootinapp.module.tsloads and validates them. Readprocess.envnowhere else. List every var in.env.example. - Entities: in the owning module, next to its repository.
infra/database/only sets up the connection and registers migrations. - Auth: a feature module (
modules/auth/). It exports its guards and providers; truly app-wide guards go incommon/guards/. - Scheduled data cleanup:
<thing>.cleanup.tsin the module that owns the data. - Pure helpers:
<name>.util.tsnext to the main user. Move tocommon/on the second user, never pre-emptively.
Tests
- Unit tests colocated:
users.service.spec.ts. Build the unit withTest.createTestingModuleand mock at module seams. - E2e tests in
test/at the app root:*.e2e-spec.tsbooting the realAppModule. - Test services, policies, and pipes directly without HTTP. Test controllers and guards through e2e.
Structure at three sizes
Read references/growth-stages.md when deciding whether to restructure.
Prototype
CLI default: feature folders directly under src/ (src/users/), no common/ or infra/.
Signal to move up: a second cross-cutting concern appears (a queue, a mailer, a guard used by two modules).
Mid-size
The default layout above. Signal to move up: a module passes ~15 files, or several modules form an obvious group.
Large
Group related modules (modules/desk/{notes,projects,tasks}/) and split big ones into submodules (modules/auth/{mfa,oidc}/). For a second deployable (worker, admin API), switch to nest-cli monorepo mode with apps/ and libs/.
Anti-patterns
Read references/anti-patterns.md when reviewing a layout or before moving files.
- Do not put business logic in controllers, resolvers, or gateways. Use services.
- Do not inject another module's repository or entity. Import the module and use its exported service.
- Do not use
forwardRefas a routine fix. Restructure. - Do not mark modules
@Global()by default. - Do not put a single-module guard, filter, or interceptor in
common/. - Do not read
process.envoutside*.config.tsfiles. - Do not return entities from controllers. Map to a DTO or serialized view.
- Do not create
utils/,helpers/, or a providerlessSharedModuledumping ground. - Do not register the same pipe globally in both
main.tsandAPP_PIPE.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

