How to Distinguish and Configure Development and Production Environments (NestJS + MySQL + TypeScript)

In the previous article https://en.blog.jasonzk.com/nestjs/nesttsmysql/, we detailed how to set up a development environment for NestJS + MySQL + TypeScript. This article builds on that by detailing how to distinguish between development and production environments, load different configurations, and use PM2 to deploy a NestJS project in a production environment.

Using Environment Variables to Distinguish Environments

First, we need to create two environment variable files in the project’s root directory: .env.development and .env.production, for the development and production environments, respectively, and install dotenv.

.env.development

Terminal window
1
NODE_ENV=development
2
DB_HOST=localhost
3
DB_PORT=3306
4
DB_USERNAME=root
5
DB_PASSWORD=password
6
DB_DATABASE=test

.env.production

Terminal window
1
NODE_ENV=production
2
DB_HOST=your-production-host
3
DB_PORT=3306
4
DB_USERNAME=your-production-username
5
DB_PASSWORD=your-production-password
6
DB_DATABASE=your-production-database

Install dotenv

Terminal window
1
npm install dotenv

Create a config directory in the src directory and a configuration.ts file within it to load the environment variables:

1
import * as dotenv from "dotenv";
2
3
const env = process.env.NODE_ENV || "development";
4
5
dotenv.config({ path: `.env.${env}` });
6
7
export default () => ({
8
environment: env,
9
database: {
10
host: process.env.DB_HOST,
11
port: parseInt(process.env.DB_PORT, 10) || 3306,
12
username: process.env.DB_USERNAME,
13
password: process.env.DB_PASSWORD,
14
database: process.env.DB_DATABASE,
15
},
16
});

Configuring Different Database Connections

Next, in src/app.module.ts, use ConfigModule and TypeOrmModule to load the database configuration:

1
import { Module } from "@nestjs/common";
2
import { ConfigModule, ConfigService } from "@nestjs/config";
3
import { TypeOrmModule } from "@nestjs/typeorm";
4
import configuration from "./config/configuration";
5
import { UsersModule } from "./users/users.module";
6
import { User } from "./users/user.entity";
7
import { AppController } from "./app.controller";
8
import { AppService } from "./app.service";
9
10
@Module({
11
imports: [
12
ConfigModule.forRoot({
13
isGlobal: true,
14
load: [configuration],
15
}),
16
TypeOrmModule.forRootAsync({
17
imports: [ConfigModule],
18
useFactory: (configService: ConfigService) => ({
19
type: "mysql",
20
host: configService.get("database.host"),
21
port: configService.get("database.port"),
22
username: configService.get("database.username"),
23
password: configService.get("database.password"),
24
database: configService.get("database.database"),
25
entities: [User],
26
synchronize: true,
27
}),
28
inject: [ConfigService],
29
}),
30
UsersModule,
31
],
32
controllers: [AppController],
33
providers: [AppService],
34
})
35
export class AppModule {}

Loading Different Configuration Files

To ensure the configuration files load correctly, set the isGlobal and load options in the forRoot method of ConfigModule. The forRootAsync method of TypeOrmModule is used to asynchronously load the configuration and get the database connection information using ConfigService.

Starting the Project in Development Environment

In the development environment, start the project using the Nest CLI’s start command:

Terminal window
1
npm run start

Deploying the Project in Production Environment

For the production environment, we recommend using PM2 to manage and run the NestJS project.

Install PM2

First, install PM2 globally:

Terminal window
1
npm install -g pm2

Configure PM2

Create an ecosystem.config.js file in the project’s root directory to configure PM2:

1
module.exports = {
2
apps: [
3
{
4
name: "my-nestjs-project",
5
script: "dist/main.js",
6
env: {
7
NODE_ENV: "development",
8
},
9
env_production: {
10
NODE_ENV: "production",
11
},
12
},
13
],
14
};

Build the Project

Before starting the project, build it:

Terminal window
1
npm run build

Start the Project Using PM2

Start the project using the following command:

Terminal window
1
pm2 start ecosystem.config.js --env production

This command starts the NestJS project in production mode according to the configuration in ecosystem.config.js.

Conclusion

This article provides a detailed guide on distinguishing between development and production environments and their configurations, including using environment variables, configuring different database connections, loading different configuration files, and using PM2 to deploy a NestJS project in a production environment. By properly distinguishing and configuring different environments, you can better manage and maintain your project, improving development and deployment efficiency.