Note: This is a previous Nest release announcement
🌟 Read about the latest release - NestJS version 10 here
Today I am thrilled to announce the official release of NestJS 9.
This is a major release spanning the entire platform, including the framework, improvements to the @nestjs/swagger
package, CLI,
and updates to the documentation.
In case you're not familiar with NestJS, it is a TypeScript Node.js framework that helps you build enterprise-grade efficient and scalable Node.js applications.
Cat in Kyiv. Photo by Valdemar Kostenko
Let's dive right in!
What's new in version 9?
This release brings lots of great features and long-awaited improvements. There are far too many to list here, but let’s take a high-level look at some of the most exciting ones.
REPL (read–eval–print loop)
REPL is a simple interactive environment that takes single user inputs, executes them, and returns the result to the user. The REPL feature lets you inspect your dependency graph and call methods on your providers (and controllers) directly from your terminal.
Nest's REPL feature was first announced in May 2022 and since then it received a bunch of improvements & updates.
<script>What would you say to a @nestframework REPL?
— Kamil Mysliwiec (@kammysliwiec) May 24, 2022
🔥 navigate through modules
✨ directly call service/repository' methods
⚡️ debug providers
all that without leaving your terminal! pic.twitter.com/q6Bd9LNPRM
To run your NestJS application in REPL mode, create a new repl.ts
file (alongside the existing main.ts
file) and add the following code inside:
import { repl } from '@nestjs/core';import { AppModule } from './app.module';async function bootstrap() { await repl(AppModule);}bootstrap();
Now in your terminal, start the REPL with the following command:
$ npm run start -- --entryFile repl## OR yarn start --entryFile repl
Hint The built-in NestJS REPL comes with a few native functions that are globally available when you start REPL. You can call
help()
to list them out.
Once it's up and running, you should see the following message in your console:
LOG [NestFactory] Starting Nest application...LOG [InstanceLoader] AppModule dependencies initializedLOG REPL initialized
And now you can start interacting with your dependencies graph. For instance, you can retrieve an AppService
(we are using the starter project as an example here) and call the getHello()
method:
> get(AppService).getHello()'Hello World!'
You can execute any JavaScript code from within your terminal, for example, assign an instance of the AppController
to a local variable, and use await
to call an asynchronous method:
> appController = get(AppController)AppController { appService: AppService {} }> await appController.getHello()'Hello World!'
To display all public methods available on a given provider or controller, use the methods()
function, as follows:
> methods(AppController)Methods: ◻ getHello
To print all registered modules as a list together with their controllers and providers, use debug()
.
> debug()AppModule: - controllers: ◻ AppController - providers: ◻ AppService
Quick demo:
Configurable module builder
If you have have ever manually created dynamic modules that are highly configurable that expose async
methods, registerAsync
, forRootAsync
, etc., you know it can be quite complicated and require quite a bit of boilerplate code.
We aim to simplify this in Nest v9, which will provide a ConfigurableModuleBuilder
class that facilitates this process and lets you construct a module "blueprint" - in just a few lines of code.
For demonstration purposes, let's create a configurable HttpClientModule
using the new ConfigurableModuleBuilder
.
Before we start, let's make sure we declare a dedicated interface that represents what options our HttpClientModule
takes in.
export interface HttpClientModuleOptions { baseUrl: string;}
With this in place, create a new dedicated file named http-client.module-definition.ts
.
In this file, let's utilize the ConfigurableModuleBuilder
to construct HttpClientModule
definition.
import { ConfigurableModuleBuilder } from '@nestjs/common';import { HttpClientModuleOptions } from './interfaces';export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = new ConfigurableModuleBuilder<HttpClientModuleOptions>().build();
And finally, let's define the actual http-client.module.ts
module file and leverage the auto-generated ConfigurableModuleClass
:
import { Module } from '@nestjs/common';import { ConfigurableModuleClass } from './http-client.module-definition';@Module({})export class HttpClientModule extends ConfigurableModuleClass {}
Extending the ConfigurableModuleClass
means that HttpClientModule
provides now both register
(for static use-cases) and registerAsync
(which allows consumers asynchronously configure that module) methods.
@Module({ imports: [ HttpClientModule.register({ baseUrl: 'https://trilon.io' }), // or alternatively: // HttpClientModule.registerAsync({ // useFactory: () => { // return { // baseUrl: 'https://trilon.io', // } // }, // inject: [...any extra dependencies...] // }), ],})export class AppModule {}
You also have the ability to inject a configuration object using the @Inject(MODULE_OPTIONS_TOKEN)
construction. Read more on this feature in the documentation.
Durable providers
Request-scoped providers may sometimes lead to increased latency since having at least 1 request-scoped provider (injected into the controller instance, or deeper - injected into one of its providers) makes the controller request-scoped as well. That means, it must be recreated (instantiated) per each individual request (and garbage collected afterwards).
HINT For instance, for 30k requests in parallel, there will be 30k ephemeral instances of the controller (and its request-scoped providers).
Having a common provider that most providers depend on (e.g., database connection), automatically converts all those providers to request-scoped providers as well. This can pose a challenge in multi-tenant applications, especially for those that have a central request-scoped "data source" provider that grabs headers/token from the request object and based on their values, retrieves the corresponding database connection/schema (specific to that tenant).
For instance, let's say you have an application alternately used by 10 different customers. Each customer has its own dedicated data source, and you want to make sure customer A will never be able to reach customer's B database. One way to achieve this could be to declare a request-scoped "data source" provider that - based on the request object - determines what's the "current customer" and retrieves its corresponding database. But, a major downside to this approach is that since most likely a large chunk of your application' components rely on the "data source" provider, they will implicitly become "request-scoped", and therefore you will undoubtedly see an impact in your apps performance.
But what if we had a better solution?
Since we only have 10 customers, couldn't we have 10 individual DI sub-trees per customer (instead of recreating each tree per request)?
If your providers don't rely on any property that's truly unique for each consecutive request (e.g., request UUID) but instead there are some specific attributes that let us aggregate them, then we have no reason to recreate the DI sub-tree on every incoming request.
This is exactly where durable providers come in handy!
Before we start flagging providers as durable, we must first register a strategy that:
- instructs Nest what those "common request attributes" are
- provides logic that groups requests, and associates them with their corresponding DI sub-trees.
import { HostComponentInfo, ContextId, ContextIdFactory, ContextIdStrategy,} from '@nestjs/core';import { Request } from 'express';// A collection of context identifiers representing separate DI sub-trees per tenantconst tenants = new Map<string, ContextId>();export class AggregateByTenantContextIdStrategy implements ContextIdStrategy { attach(contextId: ContextId, request: Request) { const tenantId = request.headers['x-tenant-id'] as string; let tenantSubTreeId: ContextId; if (tenants.has(tenantId)) { tenantSubTreeId = tenants.get(tenantId); } else { // Construct a new context id (think of a root node) tenantSubTreeId = ContextIdFactory.create(); tenants.set(tenantId, tenantSubTreeId); } // If tree is not durable, return the original "contextId" object return (info: HostComponentInfo) => info.isTreeDurable ? tenantSubTreeId : contextId; }}
Hint Similar to the request scope, durability bubbles up the injection chain. That means if A depends on B which is flagged as
durable
, A implicitly becomes durable too (unlessdurable
is explicitly set tofalse
for A provider).
Warning Note this strategy is not ideal for applications operating with a large number of tenants.
With this strategy in place, you can register it somewhere in your code (as it applies globally anyway), so for example, we could place it in the main.ts
file:
ContextIdFactory.apply(new AggregateByTenantContextIdStrategy());
As long as the registration occurs before any request hits your application, everything will work as intended.
Lastly, to turn a regular provider into a durable provider, simply set the durable
flag to true
:
import { Injectable, Scope } from '@nestjs/common';@Injectable({ scope: Scope.REQUEST, durable: true })export class CatsService {}
Similarly, for custom providers, set the durable
property in the long-hand form for a provider registration:
{ provide: 'CONNECTION_POOL', useFactory: () => { ... }, scope: Scope.REQUEST, durable: true, // <-- here}
Redis transporter
In v9, the Redis transport strategy will no longer use redis
package under the hood but instead was migrated to leverage ioredis
.
Upgraded dependencies
Nest v9 brings support for Fastify v4 and drops support for Node.js v10. Make sure to use at least the latest LTS version!
Migration from Nest v8
In order to migrate your existing project, follow the guidelines that are available here. Also, make sure to get rid of all deprecation messages that may appear in your console.
Enjoy v9!
We're excited to see how you use the latest version of NestJS.
Make sure to follow Nest on Twitter @nestframework to stay up to date with all the latest announcements!
Official NestJS Courses 📚
Level-up your NestJS and Node.js ecosystem skills in these incremental workshop-style courses, from the NestJS Creator himself, and help support the NestJS framework! 🐈
🚀 The NestJS Fundamentals Course is now LIVE and 25% off for a limited time!
We'll learn about all of the fundamental building blocks, interact with both SQL & NoSql databases, use modern Node.js application techniques, unit / e2e testing, tips, tricks, and overall best-practices!
Check out the NEW - NestJS Course Extensions now live! 🎉
- NestJS GraphQL Course (code-first & schema-first approaches) are now LIVE
- NestJS Authentication / Authorization Course now on PRE-ORDER - save 25%!
Enterprise Consulting & Support
Our official NestJS Enterprise Consulting includes a broad range of services to empower your team.
We work alongside you to meet your deadlines while avoiding costly tech debt. Challenging issue? We've got you covered.
- Providing technical guidance & architectural reviews
- Mentoring team members
- Addressing security & performance concerns
- Performing in-depth code reviews
- Long-term support (LTS) & upgrade assistance
Our goal is to help you get to market faster. Nest core team members will help you utilize best practices and choose the right strategy for unique goals. You can learn more on the enterprise.nestjs.com.
Support the NestJS Project
Nest is an MIT-licensed open source project with its ongoing development made possible thanks to the support by the community and our sponsors. Thank you!
<script>We strongly believe that someday we could fully focus on #opensource to make @nodejs world better 🚀🔥 @opencollect
— NestJS (@nestframework) April 25, 2018
👍 enjoy using @nestframework?
🙌 ask your company to support us:
🎁 https://t.co/taYS49lllr pic.twitter.com/L1O9Vf5uhS
This framework is a result of the long days, sleepless nights, and busy weekends. And we fully rely on the goodness ❤️ of the people. If you want to join them, you can read more here.
T-Shirts and hoodies
If you enjoy using NestJS and you would like to donate to our Open Source work (have your cake 🍰 and eat it), we just launched the official NestJS store 👕 where you can buy hoodies, T-shirts, and accessories!
Thank you
To all backers, sponsors, contributors, and community, thank you once again! This product is for you. And this is only the beginning of the long 🚀 story.
Become a Backer or Sponsor to Nest by donating to our open collective. ❤
Learn NestJS - Official NestJS Courses 📚
Level-up your NestJS and Node.js ecosystem skills in these incremental workshop-style courses, from the NestJS Creator himself, and help support the NestJS framework! 🐈🚀 The NestJS Fundamentals Course is now LIVE and 25% off for a limited time!
🎉 NEW - NestJS Course Extensions now live!
- NestJS Advanced Concepts Course now LIVE!
- NestJS Authentication / Authorization Course now LIVE!
- NestJS GraphQL Course (code-first & schema-first approaches) are now LIVE!
- NestJS Authentication / Authorization Course now LIVE!