'NestJS startup unbelievably slow in development
My application in dev environment is annoyingly slow in it's startup phase. I've set some debug logging on various places to see what is taking up so much time, and found that my main.ts actually uses almost 9 minutes 😱 just to get my app.module imported!
Source
import { performance } from 'perf_hooks';
const startTime = performance.now();
import { Log } from 'api/common/util/logger/log';
Log.log.info(`┌────────────────────────────────────────────────────────────┐`);
Log.log.info(`│ Starting: ${new Date().toISOString()} │`);
Log.log.info(`└────────────────────────────────────────────────────────────┘`);
// From here -------------------->
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import 'reflect-metadata';
import { existsSync, mkdirSync, writeFile } from 'fs';
import * as express from 'express';
import * as bodyParser from 'body-parser';
import * as helmet from 'helmet';
import * as morgan from 'morgan';
import * as morganBody from 'morgan-body';
// <------ to here, imports fly in as expected.
// Theese take a bit longer, but not enormously
import { Config } from './api/common/config';
import { HttpExceptionFilter } from './api/common/filters/http-exception.filter';
import { LogService } from 'api/common/util/logger/log.service';
// This one takes up the most time on startup (several minutes)
import { AppModule } from './api/app.module';
Log.log.debug(` * imports done in ${(performance.now() - startTime).toFixed(3)}ms`);
Log.log.debug(` * Memory: ${readMem()}`);
function readMem() {
const mem = process.memoryUsage();
const convert = { Kb: n => (n / 1024), Mb: n => convert.Kb(n) / 1024 };
const toHuman = (n, t) => `${convert[t](n).toFixed(2)}${t}`;
return `Used ${toHuman(mem.heapUsed, 'Mb')} of ${toHuman(mem.heapTotal, 'Mb')} - RSS: ${toHuman(mem.rss, 'Mb')}`;
}
Output
Production startup:
$ node dist/main.js
info: ┌──────────────────────────────────────────────────────────────────────────┐
info: │ Starting: 2019-01-29T13:06:13.751Z │
info: │ Memory: Used 6.54Mb of 11.70Mb - RSS: 25.33Mb │
info: │ Runtime: js │
info: └──────────────────────────────────────────────────────────────────────────┘
debug: * imports done in 6862.350ms
debug: * Memory: Used 87.99Mb of 113.76Mb - RSS: 133.58Mb
info: Nest application successfully started
info: ┌──────────────────────────────────────────────────────────────────────────┐
info: │ Memory: Used 93.71Mb of 122.52Mb - RSS: 144.20Mb │
info: │ Launch: 2019-01-29T13:06:25.377Z │
info: │ Time to start: 11991.049ms │
info: │ Bootstrap time: 5124.189ms │
info: └──────────────────────────────────────────────────────────────────────────┘
Development startup:
$ ts-node -r tsconfig-paths/register src/main.ts
info: ┌──────────────────────────────────────────────────────────────────────────┐
info: │ Starting: 2019-01-29T13:08:06.914Z │
info: │ Memory: Used 157.76Mb of 193.62Mb - RSS: 209.77Mb │
info: │ Runtime: ts │
info: └──────────────────────────────────────────────────────────────────────────┘
debug: * imports done in 471159.063ms
debug: * Memory: Used 297.45Mb of 385.35Mb - RSS: 408.90Mb
info: Nest application successfully started
info: ┌──────────────────────────────────────────────────────────────────────────┐
info: │ Memory: Used 216.64Mb of 383.35Mb - RSS: 409.11Mb │
info: │ Launch: 2019-01-29T13:16:05.521Z │
info: │ Time to start: 483228.325ms │
info: │ Bootstrap time: 12042.239ms │
info: └──────────────────────────────────────────────────────────────────────────┘
Yes, I'm starting this using ts-node, but that is what NestJS recommends for development and debugging.
Question
How can I optimize the startup so that each minor change in the backend here does not require a 10 minute procrastination? I have trouble enough with concentration as it is, this does not help.
Do I have too many modules? Will it help if I combine some? I have about 15 DB entity models each included in it's own graphql based module for readability, but many of them have circular dependencies resolved by forwardRef() injection in my module imports. Is this perhaps a problem?
I try to include as few third-party libraries as possible to avoid node_modules hell. What I import in my modules are either my own code or NestJS framework stuff. Of course I do not know how many implicit dependencies gets loaded, but could the amount of libraries I'm dragging with me impact the startup performance? And if so, how can I monitor what gets on the stack and how much memory/cpu each script consumes upon evaluation? And can I somehow precompile some of this to increase startup?
I don't have this problem when running as compiled javascript in production.
Solution 1:[1]
Try to set env TS_NODE_TRANSPILE_ONLY=true.
e.g. TS_NODE_TRANSPILE_ONLY=true ts-node -r tsconfig-paths/register src/main.ts
docs: https://github.com/TypeStrong/ts-node#cli-and-programmatic-options
It's speed up my app startup
Solution 2:[2]
One option is to use tsc-watch instead of ts-node and nodemon. You can set up the start command in your start:dev as follows:
{
//this is assuming you're building to the dist folder
...
"start:dev": "tsc-watch --onSuccess \"node dist/main.js\" --onFailure \"echo
There was a problem with the build!\" -p tsconfig.json"
...
}
In my experience I ran into too many problems with ts-node and registering routes, plus load times were killing me. With tsc-watch I get a fresh build of the project, rebuilding only the files that were changed. This way you're also testing that tsc works while developing.
I also use a tsconfig-bootstrap command to import my custom routes (defined in my tsconfig) and add that into my start command with node -r path/to/my/script.js dist/main.js.
Hope this helps you a bit!
Solution 3:[3]
I had this issue after upgrading to [email protected] and started using node v16. The problem went away after I downgraded the nodejs version.
Edit: The issue was related to the pg module. It was silently falling. After updating to pg@latest NestJs started normally.
Solution 4:[4]
If anyone is having this issue, we have an Nest API with like 40 modules, with node v12 the startup time was like 2-3 minutes, while with node v14+ startup time is between 5-10 seconds. For local development I recommend using NVM and try using a higher version of node (if packages are compatible ofc).
Solution 5:[5]
install the latest version of the @nestjs/cli, both globally and locally:
$ npm install -g @nestjs/cli
$ cd /some/project/root/folder
$ npm install -D @nestjs/cli
replace/make sure you have the below scripts defined in package.json
"build": "nest build",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
make sure you have vs code auto attach on 
run
npm run start:dev
Solution 6:[6]
A logical solution and something that works solving the problem is to uncomment the modules which you are not using currently from app module.
@Module({
imports: [
TypeOrmModule.forRoot(defaultOptions),
// Commented for faster reloads
// NotUsingModule1
// NotUsingModule2
UsingModule1
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule { }
Also In case working with RDBMS make sure logging in not set true and dropSchema is also not set true.
- In some cases you will face problem with entities not forming relations correctly make dropSchema true it will CLEAR ALL ENTITIES FROM DATABASE. DO NOT DO THAT IN PRODUCTION. YOU HAVE BEEN WARNED
export const defaultOptions = {
type: "postgres",
port: 5432,
username: "postgres",
password: "postgres",
database: "awesome db",
synchronize: true,
// logging: true,
// dropSchema: true,
entities: ['dist/**/*.entity.js'],
Solution 7:[7]
Just adding this in case someone else might have the same cause, my issue was due to importing grpc clients, both not being specific enough with which proto(s) to include and also at too many different places.
Our protos structure is quite big so was very slow for the grpc loader to load in which caused nest to take several minutes to startup.
So make sure you only use the services you directly need in the configured protoPath. I don't think the includeDirs options matters, so just the protoPath.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Diluka W |
| Solution 2 | rinogo |
| Solution 3 | |
| Solution 4 | betodevq |
| Solution 5 | Nelson Bwogora |
| Solution 6 | Chetan Jain |
| Solution 7 | Rubennaatje |
