DEV Community

Emmanuel Nwankwo
Emmanuel Nwankwo

Posted on

Env-Core: An Easy Way to Validate Environment Variables in Node.js Projects

Managing environment variables effectively is crucial in Node.js applications, but existing solutions can feel limiting or lack the flexibility needed for complex setups. Frustrated by these challenges, I developed env-core. Let me tell you about it.

Introduction to env-core

env-core is a powerful yet simple npm package for validating environment variables in Node.js applications. Built with TypeScript and compatible with Express and NestJS frameworks, env-core ensures that your configurations are always type-safe, complete, and ready for production. By leveraging dotenv as its sole dependency, env-core works to validate your environment variables before your application even starts.

Key Features

  • Type Safety: Leveraging TypeScript, env-core offers strong typing for environment variables, reducing runtime errors and improving overall code quality.
  • Seamless Integration: Compatible with both Express and NestJS, env-core is a good fit for new projects or as a replacement in existing applications.
  • Flexible Configuration: Supports various data types (e.g., strings, numbers, and booleans), allowing complex configurations to fit seamlessly into your project.
  • Default Values: Set default values for optional variables, so your app always has a fallback if a variable is missing.
  • Validation: With built-in validation, you can catch configuration errors early and avoid misconfigurations in production.
  • CommonJS and ESM Support: Works effortlessly with ESM (import) and CommonJS (require) modules, giving you flexibility based on your project setup.

Getting Started

To start using env-core in your project, simply install it via npm:

npm install env-core
Enter fullscreen mode Exit fullscreen mode

After installation, you can integrate env-core into your application with ease. Here's an example to get you started:

import { validateEnv } from 'env-core';

const env = validateEnv({
  PORT: Number,
  DATABASE_URL: String,
  DEBUG: Boolean,
});

console.log(env.PORT); // Typed as number
console.log(env.DATABASE_URL); // Typed as string
console.log(env.DEBUG); // Typed as boolean
Enter fullscreen mode Exit fullscreen mode

env-core supports both ESM and CommonJS modules, so if you’re using CommonJS, you can import it like this:

const { validateEnv } = require('env-core');
Enter fullscreen mode Exit fullscreen mode

Use Cases

env-core offers flexible configuration options based on your project’s needs. Here are three use cases that show how you can set up an environment schema with various levels of configuration:

Use Case 1: Simple Types

In this basic setup, each environment variable is typed with a primitive type.

// src/envSchema.js
export const envSchema = {
  PORT: Number,
  DATABASE_URL: String,
  DEBUG: Boolean,
  NODE_ENV: String,
};
Enter fullscreen mode Exit fullscreen mode

Use Case 2: Configuration Options

You can include default values and exclude requirement checks for specific environment variables.

Use Case 2: Configuration Options

This setup allows you to include default values and specify which variables are optional.

// src/envSchema.ts
export const envSchema = {
  PORT: { type: Number, default: 3000, required: false },
  DATABASE_URL: { type: String },
  DEBUG: { type: Boolean, default: false },
  NODE_ENV: { type: String, default: 'development', required: false },
};
Enter fullscreen mode Exit fullscreen mode

Use Case 3: Mixed Configuration

For flexibility, you can use a mix of simple types and configuration options.

// src/envSchema.ts
export const envSchema = {
  PORT: Number,
  DATABASE_URL: String,
  DEBUG: { type: Boolean, default: false },
  NODE_ENV: { type: String, default: 'production', required: false },
};
Enter fullscreen mode Exit fullscreen mode

Framework-Specific Use Cases

env-core easily integrates with Express and NestJS, making environment variable validation a simple step during the initialization process.

ExpressJS Example

In Express, validate your environment variables before starting the server:

// src/index.js
import express from 'express';
import { validateEnv } from 'env-core';
import { envSchema } from './envSchema';

const env = validateEnv(envSchema); // Option 1: Validates using environment variables or defaults to .env
// const env = validateEnv(envSchema, 'test.env'); // Option 2: Validates using a custom env file

const app = express();
app.listen(env.PORT, () => {
    console.log(`Server is running on port ${env.PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

NestJS Example

In NestJS, integrate env-core validation within the module initialization:

// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { validateEnv } from 'env-core';
import { envSchema } from './envSchema';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validate: (config) => validateEnv(envSchema, config), // Validate environment variables
    }),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Why Choose env-core?

Compared to other packages, env-core offers:

  • Type Safety: Strong typing reduces runtime errors and improves overall reliability.
  • Graceful Startup Failure: If a critical variable is missing or invalid, env-core will prevent your application from starting, allowing you to address configuration issues upfront.
  • Flexible Fallbacks: Optional fields with default values ensure that your application can adapt to different environments (e.g., staging vs. production).
  • Enhanced Clarity: By defining environment variables in a schema or interface, you gain visibility into your application’s configuration requirements.

Found env-core useful? check out the code on GitHub and consider giving it a star to show your support! Your feedback is valuable, so please don’t hesitate to open an issue if you encounter any problems or have ideas for improvements.

Top comments (0)