Discord Bot Base/Conventions

Env

Loading environment variables natively

Env File

With the latest versions of NodeJs we can use the --env-file flag to specify an environment variables file for our project.

node --env-file .env ./dist/index.js

By starting the project with this flag in the script, the process.env object will contain all the variables defined in the .env file at the root of the project.

You can have two env files in your project and choose which one to use through predefined scripts.

package.json
{
  // ...
  "scripts":{
    "dev": "tsx --env-file .env ./src/index.ts",
    "dev:dev": "tsx --env-file .env.dev ./src/index.ts",
  }
}

If you have a .env.dev file, you can run the dev:dev script.

npm run dev:dev

This is the same for all other scripts:

npm run start:dev
npm run watch:dev

This way, you can have development and production environment variables.

Validating env variables

With zod, we can create a schema for the environment variables object to validate before the project starts, thus ensuring that the information is correct and also providing Intelisense with auto-completion of the variables we have, see:

src/settings/env.schema.ts
import { z } from "zod";

export const envSchema = z.object({
    BOT_TOKEN: z.string({ description: "Discord Bot Token is required" }).min(1),
    WEBHOOK_LOGS_URL: z.string().url().optional(),
    // Env vars...
});

This schema will be used in the file by the function in the src/settings/env.validate.ts file that creates the env variable exported in the src/settings/index.ts file:

src/settings/index.ts
import settings from "../../settings.json" with { type: "json" };
import { envSchema } from "./env.schema.js"; 

import "./global.js";
import { logger } from "./logger.js";
import { validateEnv } from "./env.validate.js"; 
export * from "./error.js";

const env = validateEnv(envSchema); 

export { settings, logger, env };

When you need to use the validated and transformed environment variables, just import env from #settings:

import { env } from "#settings";

console.log(env.BOT_TOKEN);

You can set the minimum number of characters, the format, whether it should be url, email, restrict values, convert to other types, see some examples below:

src/settings/env.schema.ts
import { z } from "zod";

export const envSchema = z.object({
    BOT_TOKEN: z.string({ description: "Discord Bot Token is required" }).min(1),
    DATABASE_URL: z.string({ description: "Database URL is required" }).url() 
    WEBHOOK_LOGS_URL: z.string().url().optional(),
    // Env vars...
});

With this in mind, when working with more tools or libraries that require sensitive information stored in the .env file, simply add the necessary validations to the schema.

On this page