Skip to content
masterclassBuddyTech Buzz5 fresh blogs · 5:00 AM IST

Technology handbook

Nest.js Packages — Decorators, Providers & Modules

110 Nest building blocks: the official packages, every decorator you apply, and the pipes, guards, interceptors and filters that make up the request pipeline.

Topics
110
Sections
12

Core packages

@nestjs/core

The framework runtime: the DI container, module resolution, lifecycle and NestFactory.

  • The framework runtime holds the injection container and the request pipeline.
  • It is what turns decorated classes into a running application.
  • Everything else is layered on it, so its version anchors the rest.

@nestjs/common

Everything you import daily — decorators, pipes, guards, interceptors, exceptions and HttpModule helpers.

  • Decorators, pipes, guards and exceptions that application code uses daily.
  • Nearly every file imports from here rather than from core.
  • Its version must match core or decorator metadata disagrees.

@nestjs/platform-express

The default HTTP adapter. Express middleware and its ecosystem work unchanged underneath.

  • Express serves HTTP beneath the framework abstraction.
  • It is the default, so most middleware examples assume it.
  • Reaching for the raw request couples code to this platform.

@nestjs/platform-fastify

The Fastify adapter, for meaningfully higher throughput at the cost of Express-specific middleware.

  • Fastify replaces Express as the HTTP layer.
  • It is faster and stricter, which is the reason to switch.
  • Express-specific middleware does not carry over.

@nestjs/config

Typed configuration from env and files, with schema validation and namespaced registerAs factories.

  • Environment configuration is loaded, validated and injected.
  • Validating at boot turns a missing variable into a startup failure.
  • Reading process.env directly scatters the contract across the codebase.

@nestjs/swagger

Generates OpenAPI from decorators and DTOs, and serves Swagger UI.

  • OpenAPI documents are generated from decorators and DTOs.
  • Generating from code is what stops the document drifting from the routes.
  • Erased types need explicit decorators to appear at all.

@nestjs/cli

Scaffolding, build and the schematics behind nest generate.

  • Projects, modules and providers are scaffolded and built.
  • Generation enforces the conventions the framework expects.
  • Generated files still need wiring into the right module.

@nestjs/mapped-types

PartialType, PickType, OmitType and IntersectionType for deriving DTOs without copying them.

  • New DTOs derive from existing ones by picking or omitting fields.
  • Deriving keeps validation rules in one place.
  • A derived type inherits decorators, including ones that no longer apply.

@nestjs/terminus

Health check endpoints with indicators for databases, disk, memory and HTTP dependencies.

  • Health checks are exposed as a route with pluggable indicators.
  • A health endpoint is what an orchestrator uses to decide readiness.
  • A check that touches a dependency makes that dependency part of liveness.

@nestjs/event-emitter

In-process domain events with @OnEvent, for decoupling side effects from the request path.

  • In-process events decouple a producer from its consumers.
  • Decoupling keeps unrelated work out of the request path.
  • Events are lost on restart, unlike a queue.

@nestjs/schedule

@Cron, @Interval and @Timeout declarative scheduling with a lifecycle-aware registry.

  • Cron jobs, intervals and timeouts are declared with decorators.
  • Declaring them keeps scheduling visible beside the code it runs.
  • Every instance runs the job unless a lock prevents it.

@nestjs/bullmq

Redis-backed queues wired into DI, with @Processor and @OnWorkerEvent decorators.

  • Redis-backed queues run background jobs with retries.
  • A queue survives restarts, which an in-process event does not.
  • Redis becomes a hard dependency of the application.

@nestjs/cache-manager

Response and method caching with pluggable stores and the @CacheKey/@CacheTTL decorators.

  • Responses and values are cached behind a common interface.
  • One interface is what allows memory and Redis to swap.
  • A cached response can outlive the permission that allowed it.

@nestjs/throttler

Rate limiting as a guard, configurable globally or per route with @Throttle.

  • Request rate limits are applied per route or globally.
  • Limiting is what blunts brute force and abuse.
  • An in-memory counter is per instance, not per cluster.

Module system

@Module()

Declares imports, controllers, providers and exports — the unit the DI container resolves.

  • Controllers, providers, imports and exports are declared together.
  • A provider is injectable only where its module is imported or exported.
  • The module graph is the real architecture, not the folder layout.

@Global()

Makes a module's exported providers available everywhere without re-importing. Use sparingly.

  • A module's exports become available everywhere without importing.
  • It removes repetitive imports for genuinely cross-cutting modules.
  • It also hides dependencies, which is why it is used sparingly.

Dynamic modules

forRoot/forFeature static factories that return a module configured at import time.

  • A module is configured by the code importing it.
  • Configuration at import is what makes a module reusable.
  • Registering the same dynamic module twice can duplicate providers.

ConfigurableModuleBuilder

Generates the forRoot/forRootAsync boilerplate for a configurable module.

  • Boilerplate for sync and async module options is generated.
  • It produces the register and registerAsync pair consistently.
  • The generated names are conventional and must be followed.

forwardRef()

Resolves a genuine circular dependency between two modules or providers. A sign to reconsider the boundary.

  • A circular dependency between modules or providers is resolved.
  • It defers resolution until both sides exist.
  • A circular dependency is usually a design problem this merely defers.

ModuleRef

Resolves providers imperatively at runtime, including scoped ones outside a request.

  • Providers are resolved from the container at runtime.
  • It is the escape hatch when a dependency is only known then.
  • Resolving a scoped provider returns a new instance each call.

Lazy modules

LazyModuleLoader defers instantiation until first use, which matters for serverless cold starts.

  • A module loads on first use rather than at boot.
  • It shortens cold start where a feature is rarely reached.
  • The first request to that feature pays the load cost.

Controllers & routing

@Controller()

Binds a class to a route prefix and marks it as the HTTP entry point for its handlers.

  • A class handles requests under a route prefix.
  • The prefix is what groups related routes without repeating the path.
  • Business logic here cannot be reused by a queue consumer.

@Get / @Post / @Put / @Patch / @Delete

Map a method to an HTTP verb and a path, including parameters and wildcards.

  • Methods bind to HTTP verbs and sub-paths.
  • The verb is part of the contract, not decoration.
  • Route order matters, so a wildcard declared early shadows later routes.

@All / @Head / @Options

The remaining verb decorators, for catch-alls and preflight handling.

  • Less common verbs and catch-all handlers are declared.
  • OPTIONS matters for CORS preflight handling.
  • @All catches everything, including verbs you meant to reject.

@Param()

Extracts a route parameter, optionally through a pipe such as ParseIntPipe.

  • Route parameters are injected into the handler.
  • Injecting by name keeps the handler independent of the request object.
  • Every value arrives as a string until a pipe converts it.

@Query()

Extracts the parsed query string, whole or by key.

  • Query string values are injected.
  • A repeated key yields an array, which the DTO must allow for.
  • Query input is untrusted and needs the same validation as a body.

@Body()

Extracts the parsed request body — the usual place a validation pipe runs.

  • The parsed request body, or one property of it, is injected.
  • Binding to a DTO class is what makes validation possible.
  • Body parsing must be enabled and size-limited.

@Headers()

Extracts request headers, whole or by name.

  • Request headers are injected by name or as a whole.
  • Header names are case-insensitive, which the lookup handles.
  • Any header a client sends is untrusted input.

@Req() / @Res()

The underlying platform request and response. Taking @Res() opts out of Nest's response handling.

  • The underlying platform request and response are injected.
  • It is the escape hatch for what the framework does not expose.
  • Using @Res() disables the framework's own response handling.

@Session()

The session object, once session middleware is installed.

  • The session object is injected into the handler.
  • It requires session middleware to be configured first.
  • Session state is server-side and must be stored somewhere real.

@Ip() / @HostParam()

Client IP and subdomain parameters for host-based routing.

  • The client address and host sub-domain parameters are injected.
  • Host parameters are how multi-tenant subdomain routing works.
  • Behind a proxy the address is the proxy's unless trust is configured.

@HttpCode()

Overrides the success status code, which otherwise defaults to 200 or 201 on POST.

  • The success status code for a handler is set.
  • POST defaults to 201, which is often not what an action returns.
  • It sets the success code only, not the error codes.

@Header()

Sets a static response header on a handler.

  • A response header is added declaratively.
  • Declaring it keeps the header beside the route that needs it.
  • It applies to the success path, not to thrown exceptions.

@Redirect()

Declares a redirect, with the target overridable from the return value.

  • The handler responds with a redirect.
  • The target and status can be overridden by the returned value.
  • A redirect to a user-supplied URL is an open redirect.

@Render()

Renders a server-side template with the returned object as its model.

  • A server-side template renders with the returned data.
  • It requires a view engine to be configured on the application.
  • It is incompatible with returning JSON from the same handler.

@Sse()

Turns a handler returning an Observable into a Server-Sent Events stream.

  • The handler streams server-sent events from an observable.
  • It is the simplest push mechanism, needing no extra protocol.
  • Proxies may buffer the stream unless configured not to.

RouterModule

Declares route hierarchies across modules so prefixes live in one place.

  • Module route prefixes are declared in one hierarchy.
  • Centralising them is what keeps a large route tree comprehensible.
  • It duplicates path knowledge that also lives on the controllers.

Versioning

URI, header, media-type or custom API versioning, set globally and overridden with @Version().

  • Multiple API versions are served by URI, header or media type.
  • Versioning is what lets a breaking change ship without breaking clients.
  • Every version supported is a version that must be maintained.

Providers & DI

@Injectable()

Marks a class as a provider the container may construct and inject.

  • A class becomes a provider the container can construct.
  • The decorator is what emits the metadata injection relies on.
  • A class without it cannot receive constructor dependencies.

@Inject()

Injects by token rather than by type — for interfaces, constants and factory results.

  • A dependency is injected by token rather than by type.
  • Tokens are needed for interfaces and values, which have no runtime type.
  • A mistyped token fails at startup, not at the call site.

@Optional()

Allows a dependency to be missing instead of failing resolution.

  • A missing dependency resolves to undefined instead of failing.
  • It allows a provider to work with or without an optional collaborator.
  • It turns a wiring mistake into a silent undefined.

useClass / useValue / useFactory / useExisting

The four provider shapes: swap an implementation, supply a constant, compute one, or alias another token.

  • A token is bound to a class, a value, a factory or an alias.
  • useFactory is what allows a provider built from configuration.
  • useValue objects are shared, so mutating one affects every consumer.

Injection scopes

DEFAULT singletons, REQUEST per request and TRANSIENT per consumer. Request scope bubbles up and costs performance.

  • A provider is a singleton, per request, or transient.
  • Singleton is the default, which is why per-request state leaks.
  • A request-scoped provider makes everything depending on it request-scoped.

@INQUIRER

Injects the consuming class into a transient provider — the trick behind contextual loggers.

  • A provider learns which class asked for it.
  • It is how a logger labels itself with its consumer automatically.
  • It requires transient scope, so the provider is no longer shared.

Custom decorators

createParamDecorator builds reusable extractors such as @CurrentUser().

  • Parameter and metadata decorators remove repeated plumbing.
  • A parameter decorator keeps the handler signature honest.
  • Metadata decorators do nothing until a guard reads them.

Lifecycle hooks

OnModuleInit, OnApplicationBootstrap, OnModuleDestroy, BeforeApplicationShutdown, OnApplicationShutdown.

  • Modules and providers run code on init and destroy.
  • onModuleInit is where connections belong, not the constructor.
  • Shutdown hooks only run if they are explicitly enabled.

DiscoveryService

Enumerates providers and their metadata at runtime, which is how decorator-driven plugins find their handlers.

  • Providers and controllers are enumerated at runtime.
  • It is how a library finds everything carrying its decorator.
  • Scanning happens once at boot, so late registrations are missed.

Pipes & validation

ValidationPipe

Validates and transforms DTOs with class-validator. Set whitelist and forbidNonWhitelisted to drop unexpected fields.

  • whitelist: true strips properties that carry no validation decorator.
  • forbidNonWhitelisted turns those extra properties into a rejected request instead.
  • Without either, unexpected properties reach the handler untouched.

ParseIntPipe / ParseFloatPipe

Coerce a string parameter to a number, or throw 400 if it will not convert.

  • A string parameter becomes a number or the request fails.
  • Failing at the boundary keeps the handler free of parsing.
  • An empty string and a missing value fail differently.

ParseBoolPipe

Coerces 'true'/'false' to a boolean with a proper error otherwise.

  • A string becomes a real boolean.
  • Only recognised spellings convert; anything else is rejected.
  • Truthiness on the raw string would make the word false true.

ParseUUIDPipe

Rejects an identifier that is not a well-formed UUID before it reaches the database.

  • A parameter is validated as a UUID of a given version.
  • Rejecting early stops a malformed id reaching the database.
  • It validates the shape, not that the record exists.

ParseEnumPipe

Restricts a value to the members of an enum.

  • A value is constrained to the members of an enum.
  • The enum is the allowed set, so the check cannot drift from it.
  • It compares values, not the enum key names.

ParseArrayPipe

Parses and validates a delimited or JSON array, item type included.

  • A delimited value becomes a typed array with each item validated.
  • It handles the repeated-query-parameter case consistently.
  • A single value may arrive unwrapped unless the pipe is told to expect an array.

ParseFilePipe

Validates uploads by size and MIME type with MaxFileSizeValidator and FileTypeValidator.

  • An uploaded file is validated for size and type.
  • Validating before writing is what stops a hostile upload landing.
  • Declared content type is client-supplied and can be wrong.

DefaultValuePipe

Supplies a fallback before other pipes run, so optional query parameters stay simple.

  • A missing value is replaced with a default before other pipes run.
  • Ordering matters, because a parse pipe would otherwise fail on undefined.
  • It only fills undefined, not an empty string.

class-validator

The decorator vocabulary — @IsString, @IsEmail, @Min, @ValidateNested and the rest.

  • DTO fields carry validation rules as decorators.
  • Rules beside the field keep the contract readable.
  • It needs real classes, because interfaces leave no runtime metadata.

class-transformer

plainToInstance and @Exclude/@Expose for shaping what leaves the API.

  • Plain payloads become class instances and back again.
  • Instances are what validation and serialization both operate on.
  • Transformation runs before validation, so a bad cast surfaces as a validation error.

nestjs-zod

Zod schemas as DTOs, with OpenAPI generation, for teams that prefer schemas to decorators.

  • Zod schemas replace decorator-based DTO validation.
  • One schema gives both the runtime check and the inferred type.
  • It is a different model from class-validator and mixing them confuses.

Guards & auth

@UseGuards()

Attaches guards to a handler, controller or the whole app. Guards run before interceptors and pipes.

  • Guards run global first, then controller, then route, in binding order.
  • They run after middleware and before interceptors and pipes.
  • Returning false yields a generic refusal unless an exception is thrown instead.

CanActivate

The guard interface: return true, false or a promise, with the ExecutionContext for the request.

  • A guard implements a single method returning whether to proceed.
  • It receives the execution context, so it works beyond HTTP.
  • Returning false yields a generic refusal unless an exception is thrown.

@nestjs/passport

Wraps Passport strategies as injectable guards via AuthGuard('jwt').

  • Passport strategies integrate as guards and providers.
  • It brings a large ecosystem of authentication mechanisms.
  • The strategy's validate return becomes the request user.

@nestjs/jwt

Signs and verifies JWTs with an injectable JwtService and async configuration.

  • Tokens are signed and verified through an injectable service.
  • Configuration lives in one module rather than at each call site.
  • A token cannot be revoked before expiry, so lifetimes must be short.

PassportStrategy

The base class for a custom strategy whose validate() result becomes request.user.

  • A strategy class wraps a Passport strategy with validation.
  • The class form is what allows dependency injection inside it.
  • The strategy name is what links a guard to the mechanism.

Reflector

Reads metadata set by custom decorators — the mechanism behind role and permission checks.

  • Metadata set by decorators is read at runtime.
  • It is how a guard discovers what a route requires.
  • Reading from the wrong target returns undefined rather than failing.

@SetMetadata()

Attaches arbitrary metadata to a handler for a guard or interceptor to read back.

  • Arbitrary metadata is attached to a handler or class.
  • It is the mechanism a custom guard's rules are declared with.
  • A raw key is stringly typed, so a wrapper decorator is safer.

Roles / Permissions pattern

A @Roles() decorator plus a guard reading it through Reflector — Nest's canonical authorisation shape.

  • A decorator declares requirements and a guard enforces them.
  • Separating declaration from enforcement keeps rules beside the route.
  • The guard must be registered or the decorator does nothing.

@nestjs/casl

Attribute-based permissions where rules are defined per subject and action rather than per route.

  • Ability rules express what a subject may do to a resource.
  • Rules are data, so they can be composed and tested alone.
  • Defining abilities per request costs on every request.

Interceptors & filters

@UseInterceptors()

Wraps a handler to transform its result, extend behaviour or short-circuit it.

  • A pre-controller interceptor runs global, then controller, then route.
  • The post-request pass runs the other way round: route, controller, global.
  • That wrapping is what lets one interceptor time the whole handler.

NestInterceptor

intercept(context, next) returning an Observable — logging, timeouts, caching and serialisation live here.

  • Behaviour is added before and after the handler through an observable.
  • Returning the stream unchanged is what makes it transparent.
  • Forgetting to return the stream hangs the request.

ClassSerializerInterceptor

Applies class-transformer on the way out, which is how @Exclude() keeps passwords out of responses.

  • Responses are serialized according to class decorators.
  • Excluding a field on the entity is safer than omitting it per route.
  • It only applies to class instances, not to plain objects.

TimeoutInterceptor

Applies an RxJS timeout so a stuck dependency returns 408 instead of hanging.

  • A handler exceeding a duration is aborted.
  • A bound is what stops one slow dependency exhausting the server.
  • Aborting the response does not cancel the work already started.

FileInterceptor / FilesInterceptor

Multer-backed upload handling bound to a field name.

  • Multipart uploads are parsed into file objects.
  • Limits are configured here rather than inside the handler.
  • Without a size limit an upload can exhaust disk or memory.

@UseFilters()

Attaches exception filters that turn thrown errors into responses.

  • Exception filters resolve route first, then controller, then global.
  • They are the last stage before the response is sent.
  • A filter catches what was thrown, so it cannot alter a successful response.

ExceptionFilter

catch(exception, host) for mapping domain errors to HTTP or RPC responses.

  • Errors are caught and turned into a chosen response shape.
  • One shape for every error is what clients can actually rely on.
  • Catching everything can swallow framework errors that should surface.

HttpException

The base error class, with BadRequestException, NotFoundException, ForbiddenException and the rest built on it.

  • An HTTP error is thrown with a status and a body.
  • Throwing is what lets deep code produce a correct response.
  • A non-HTTP error becomes a 500 unless a filter maps it.

BaseExceptionFilter

Extend it to add behaviour — reporting, say — while keeping the default response mapping.

  • A custom filter extends the built-in behaviour.
  • Extending keeps the default handling for what it does not cover.
  • Not delegating upward loses the framework's own error responses.

Middleware

NestMiddleware

Classic (req, res, next) middleware as an injectable class, so it can take dependencies.

  • Middleware is the first stage, running globally bound before module bound.
  • It runs before guards, so it cannot see a resolved user.
  • It is the right place only for genuinely transport-level concerns.

configure(consumer)

MiddlewareConsumer binds middleware to routes, with exclude() and forRoutes().

  • Middleware is bound to routes inside a module.
  • Binding per module is what keeps middleware scoped.
  • Route matching here is path-based, not decorator-based.

Functional middleware

A plain function when no dependencies are needed — cheaper and easier to test.

  • A plain function serves as middleware.
  • It is simpler when no dependency injection is needed.
  • It cannot receive injected providers.

Global middleware

app.use() for things that must run before routing, such as raw-body capture for webhooks.

  • Middleware applies to every request from the application instance.
  • It is registered outside any module, so it cannot inject providers.
  • It also runs for routes that should never reach it.

Execution order

Middleware, then guards, then interceptors, then pipes, then the handler — and interceptors again on the way out.

  • Middleware, then guards, then pre-controller interceptors, then pipes, then the handler.
  • Post-request interceptors and exception filters run in reverse: route, controller, global.
  • Interceptors run before pipes, so an interceptor cannot see a transformed parameter.

Data & persistence

@nestjs/typeorm

forRoot/forFeature wiring, @InjectRepository and transaction support.

  • TypeORM entities and repositories integrate with the container.
  • Repositories are injected rather than constructed.
  • Synchronize is convenient in development and dangerous in production.

@nestjs/sequelize

Sequelize models registered as providers with @InjectModel.

  • Sequelize models integrate with the injection container.
  • Model injection keeps data access out of the constructor.
  • Its typing is weaker than the alternatives.

nestjs-prisma

A PrismaService wrapped as an injectable module with lifecycle hooks.

  • The Prisma client becomes an injectable service.
  • One client instance is shared rather than created per request.
  • Its lifecycle must be tied to the module's shutdown hook.

@Transaction patterns

Unit-of-work via a request-scoped transaction provider or an interceptor around the handler.

  • Dependent writes run atomically inside a transaction.
  • Every query must use the transaction handle or it runs outside it.
  • A transaction held across a network call holds locks for that long.

Repository pattern

Keeping ORM entities behind an interface so the domain does not depend on the driver.

  • Data access sits behind an interface the service depends on.
  • The interface is what lets a test substitute the store.
  • An abstraction over one ORM often just renames it.

Microservices & transport

@nestjs/microservices

A transport-agnostic RPC layer with @MessagePattern and @EventPattern handlers.

  • Services communicate over transports other than HTTP.
  • The same controllers and providers serve message patterns.
  • Message-based errors do not map onto HTTP status codes.

ClientProxy

The outbound side: send() for request/response, emit() for fire-and-forget.

  • Messages and events are sent to another service.
  • send expects a reply; emit does not.
  • The connection must be established before the first send.

TCP transport

The default transport — simplest to run, with no broker to operate.

  • The built-in transport needs no external broker.
  • It is the simplest way to split a monolith in two.
  • There is no persistence, so a message to a down service is lost.

Redis transport

Pub/sub messaging over Redis, suitable for events rather than durable work.

  • Redis pub/sub carries messages between services.
  • It is lightweight and usually already present.
  • Pub/sub does not persist, so a subscriber that is down misses messages.

NATS transport

Lightweight messaging with queue groups for load-balanced consumers.

  • NATS carries messages with subject-based routing.
  • Its request-reply and queue groups map onto the framework's patterns.
  • Core NATS is at-most-once unless JetStream is used.

Kafka transport

Partitioned, durable event streaming with consumer groups and replay.

  • Kafka carries events as a durable, replayable log.
  • Replayability is what distinguishes it from a queue.
  • Consumer groups and offsets are concepts the transport does not hide.

RabbitMQ transport

AMQP queues with acknowledgements, dead-lettering and prefetch control.

  • AMQP queues carry work with acknowledgements.
  • Acknowledgement is what makes redelivery possible.
  • Exchange and routing configuration lives outside the application.

gRPC transport

Protobuf-defined services with streaming, generated from .proto files.

  • Services communicate through protobuf-defined contracts.
  • The contract is a schema both sides are generated from.
  • The proto file becomes a build dependency to keep in step.

Hybrid application

connectMicroservice() on an HTTP app so one process serves both.

  • One process serves HTTP and a microservice transport together.
  • It allows incremental adoption without a second deployment.
  • Both listeners share a process, so one can starve the other.

GraphQL & realtime

@nestjs/graphql

Code-first or schema-first GraphQL with resolvers as providers.

  • A GraphQL schema is built code-first or schema-first.
  • Code-first infers the schema from decorated classes.
  • Resolvers are providers, so injection works as elsewhere.

@Resolver / @Query / @Mutation

Bind a class to a type and its methods to root fields.

  • Root fields are bound to resolver methods.
  • The resolver class is scoped to the type it resolves.
  • Mutations run serially at the top level; queries do not.

@ResolveField()

Resolves a field lazily — the hook where DataLoader batching belongs.

  • A field is resolved by its own method.
  • It is where a relation is fetched lazily.
  • It is the usual source of the N+1 problem.

@ObjectType / @InputType / @Field

Code-first schema definitions generated from TypeScript classes.

  • Schema types are declared from TypeScript classes.
  • Inputs and outputs are deliberately separate types.
  • Erased types need explicit field types to appear in the schema.

@Args() / @Context() / @Parent()

The resolver parameter decorators, mirroring the HTTP ones.

  • Arguments, request context and the parent object are injected.
  • Context is where per-request loaders and identity live.
  • Parent is undefined on a root field, which is easy to forget.

@nestjs/apollo

The Apollo Server driver, including federation subgraph and gateway drivers.

  • Apollo Server drives the GraphQL layer.
  • Its plugin lifecycle is where cross-cutting concerns attach.
  • It is the heaviest of the driver options.

@nestjs/mercurius

The Fastify-native GraphQL driver, for lower overhead.

  • Mercurius drives GraphQL on top of Fastify.
  • It suits an application already committed to Fastify.
  • It is tied to that platform rather than being neutral.

@nestjs/websockets

Gateways with @WebSocketGateway, @SubscribeMessage and @WebSocketServer.

  • Gateways handle websocket connections with decorators.
  • The same guards and pipes apply as on HTTP.
  • Connection state lives per instance, which affects scaling.

Subscriptions

@Subscription over a PubSub implementation; use Redis PubSub once you run more than one instance.

  • Clients receive pushed GraphQL updates over a transport.
  • It is the third operation type alongside query and mutation.
  • Fan-out across instances needs a shared pub/sub backend.

Testing & tooling

@nestjs/testing

Test.createTestingModule builds a container where any provider can be overridden.

  • A testing module builds the container with substitutes.
  • It constructs the real graph, which is what makes the test meaningful.
  • The module must be closed or handles leak between suites.

overrideProvider()

Swaps a real dependency for a double without touching the module under test.

  • A provider is replaced with a fake for the test.
  • Overriding is what isolates the unit under test.
  • Overriding too much tests the mocks rather than the code.

createNestApplication()

Boots a full app in a test so supertest can drive real HTTP through the whole pipeline.

  • A full application is bootstrapped for end-to-end tests.
  • Only this runs pipes, guards, interceptors and filters together.
  • It is much slower than a unit test, so it is used sparingly.

Custom decorator testing

Exercise the guard or interceptor that reads the metadata, not the decorator itself.

  • A decorator is exercised through a route rather than called directly.
  • Decorators only have meaning inside the framework's pipeline.
  • Calling the underlying function directly tests nothing about the binding.

nest build / nest start

The CLI build and watch commands, with SWC available for much faster rebuilds.

  • The project compiles and runs through the CLI.
  • Watch mode is what makes the development loop fast.
  • The build output layout must match the start script's expectation.

nest generate

Schematics for modules, controllers, services, resolvers and full CRUD resources.

  • Modules, controllers, services and more are scaffolded.
  • Generation applies the conventions the framework expects.
  • It also updates the owning module, which hand-written files do not.

Ask follow-up questions on any topic in your dashboard.

Start learning