#How to get ENV Vars using configService and help with possible bad practices in dynamic main.ts

21 messages · Page 1 of 1 (latest)

dusty goblet
#

Is this a bad practices? If so, how to do ?

const logger = new Logger("Bootstrap");

async function bootstrap(): Promise<void> {
  const tmpApp = await NestFactory.createApplicationContext(AppModule);

  const configService =
    tmpApp.get<ConfigService<EnvGlobalConfig, true>>(ConfigService);

  const { nodeEnv, port } =
    configService.get<EnvGlobalConfig["server"]>("server");

  await tmpApp.close();

  let app: NestExpressApplication;

  if (nodeEnv === "production") {
    app = await NestFactory.create<NestExpressApplication>(AppModule);

    app.use(helmet());
  } else {
    app = await NestFactory.create<NestExpressApplication>(AppModule, {
      httpsOptions: {
        key: readFileSync(join(__dirname, "..", "secrets", "dev-key.pem")),
        cert: readFileSync(join(__dirname, "..", "secrets", "dev-cert.pem")),
      },
    });
  }

  app.use(cookieParser());

  app.useStaticAssets(join(__dirname, "..", "public"));
  app.setBaseViewsDir(join(__dirname, "..", "views"));
  app.setViewEngine("hbs");

  await app.listen(port);

  logger.log(`Application running in ${nodeEnv} mode on port ${port}`);
  logger.log(`Application URL: http://localhost:${port}`);
}

void bootstrap();
dusty goblet
#

How to get ENV Vars using configService and help with possible bad practices in dynamic main.ts

#

And I also want to know how I can get the ENV VAR, before creating the app.

sage glacier
#

With the help of AI:

#
// Refactored (After)
import { Logger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { NestFactory } from "@nestjs/core";
import type { NestExpressApplication } from "@nestjs/platform-express";
import cookieParser from "cookie-parser";
import helmet from "helmet";
import { join } from "path";
import * as fs from "fs";

import { AppModule } from "./app.module";
import type { EnvGlobalConfig } from "./configs/types";

const logger = new Logger("Bootstrap");

async function bootstrap(): Promise<void> {
  // ✅ Simplified: Get NODE_ENV from process.env directly
  const isDev = process.env.NODE_ENV === "development";
  let app: NestExpressApplication;

  // ✅ Streamlined: Create a single application instance
  if (isDev) {
    const httpsOptions = {
      key: fs.readFileSync("./secrets/dev-key.pem"),
      cert: fs.readFileSync("./secrets/dev-cert.pem"),
    };
    app = await NestFactory.create<NestExpressApplication>(AppModule, {
      httpsOptions,
    });
    logger.log("Starting in HTTPS mode (development)");
  } else {
    app = await NestFactory.create<NestExpressApplication>(AppModule);
    logger.log("Starting in HTTP mode (production, behind reverse proxy)");
  }

  // ✅ Efficient: Get ConfigService from the main app instance
  const configService = app.get<ConfigService<EnvGlobalConfig, true>>(ConfigService);
  const { nodeEnv, port } = configService.get<EnvGlobalConfig["server"]>("server");

  // ✅ Consolidated: Middleware is applied in one place
  if (!isDev) {
    app.use(helmet());
  }
  app.use(cookieParser());

  // Static Assets and Templating (No change needed)
  app.useStaticAssets(join(__dirname, "..", "public"));
  app.setBaseViewsDir(join(__dirname, "..", "views"));
  app.setViewEngine("hbs");

  await app.listen(port);

  logger.log(`Application running in ${nodeEnv} mode on port ${port}`);
  logger.log(`Application URL: ${isDev ? "https" : "http"}://localhost:${port}`);
}

void bootstrap();
dusty goblet
sage glacier
#

What reasons do you need the configService from the app, before the app builds the configService?

dusty goblet
#

And also since you asked, it's not relevant to the problem now, but I remembered that with micro services we also need environment variables before the app is created, such as port, etc., and this is also bad because I don't know how to get the configService before creating the "app".

sage glacier
#

And, what is the issue of setting the process.env.NODE_ENV?

dusty goblet
sage glacier
#

Leave NODE_ENV to process.env. Do the rest of the config via your configService. Standard practice. You can even set up your config via the actual environment. development, ci, testing, production, etc.

dusty goblet
#

Maybe I could try this too

const httpsOptions = {
  key: fs.readFileSync('./secrets/private-key.pem'),
  cert: fs.readFileSync('./secrets/public-certificate.pem'),
};

const server = express();
const app = await NestFactory.create(AppModule, new ExpressAdapter(server));
await app.init();

const httpServer = http.createServer(server).listen(3000);
const httpsServer = https.createServer(httpsOptions, server).listen(443);
#

But if I don't find it pleasant, I'll just use process.env straight away.

#

But, thanks any way

sage glacier
#

@dusty goblet - On the topic of microservices, in that case, you should also be in charge of the environment where the microservice is running and that environment is 99% created in an automated system like k8s, so that is why you'd use the process.env for global config.

rustic marsh
#

@dusty goblet sliding in from the side here, if you are strictly looking to test https, the caddy web server is absolutely excellent at this, and its much easier to configure than any of the other web services.

Its quite a handy tool, even for development

dusty goblet
#

For dev mode I use a local key.pem and cert.pem and for production the reverse proxy already has https so I don't see any use in what you said but thanks for the tip.