Lesson 20 of 5018 min read

How to Use Environment Variables in NestJS with .env Files

Learn what environment variables are, how to set up a .env file in NestJS, and best practices for keeping secrets safe across different environments.

Author: CodersNexus

How to Use Environment Variables in NestJS with .env Files

This final lesson in Module 2 zooms in specifically on .env files themselves: what they are at a fundamental level, how they fit into the broader configuration management approach covered in the previous lesson, and the practical conventions and security practices every NestJS developer should follow from day one.

While the previous lesson focused on @nestjs/config's ConfigModule and ConfigService, this lesson focuses on the .env file itself: its syntax, common pitfalls, and how to manage multiple environment files as a project grows from local development through staging and into production.

NestJS Environment Variables .env: Learning Objectives

  • Understand what environment variables are at the operating system level.
  • Write a properly formatted .env file for a NestJS project.
  • Correctly exclude .env files from version control using .gitignore.
  • Manage multiple environment-specific .env files for development, staging, and production.
  • Recognize common mistakes and security risks around environment variable handling.

NestJS Environment Variables .env: Key Terms and Definitions

  • Environment variable: A key-value pair available to a running process, provided by the operating system or a process manager, used to configure behavior without changing code.
  • .env file: A plain text file, typically at a project's root, defining environment variables in a KEY=value format, loaded into process.env when an application starts.
  • dotenv: The underlying Node.js library that reads a .env file and loads its contents into process.env.
  • .gitignore: A file specifying which files and folders Git should never track or commit, commonly used to exclude .env files containing secrets.
  • .env.example: A template file listing all required environment variable names with placeholder or empty values, safely committed to version control to guide other developers.

How NestJS Environment Variables .env Works: Detailed Explanation

At the operating system level, an environment variable is simply a named value available to any running process, historically used for things like PATH (which directories contain executable programs) or HOME (a user's home directory). Node.js applications, including NestJS applications, access these variables through the global process.env object, where every environment variable appears as a string property.

Manually setting environment variables directly in your terminal every time you start a development server is tedious and error-prone, especially as the number of required variables grows. This is the exact problem a .env file solves: it lets you define all your environment variables in a single, plain text file at your project's root, using a simple KEY=value syntax, one variable per line, such as DATABASE_URL=postgresql://localhost:5432/mydb or PORT=3000. When your NestJS application starts, either through @nestjs/config's ConfigModule or a plain dotenv.config() call, this file is read and its contents are loaded into process.env, exactly as if you had set them manually in your terminal.

A critical, non-negotiable practice is excluding your .env file from version control using .gitignore. Since .env files commonly contain sensitive values like database passwords, API keys, and JWT signing secrets, accidentally committing this file to a public (or even private) Git repository can expose these secrets to anyone with access to the repository's history, a mistake that has caused real security incidents at real companies. The standard convention is committing a .env.example file instead, listing every required variable name with a placeholder or empty value, giving other developers on the team a clear template to create their own local .env file from, without ever exposing actual secret values.

As a project matures beyond local development, it typically needs distinct configuration for different environments: a development .env pointing to a local database, a staging .env pointing to a staging environment's resources, and a production .env (usually managed through a deployment platform's secret management system rather than a literal file) pointing to live production infrastructure. Many teams manage this using separate files like .env.development and .env.production, loaded conditionally based on the current NODE_ENV value, ensuring the exact same codebase behaves correctly and safely across every stage of the deployment pipeline without a single line of source code needing to change.

Interview-Friendly Explanation

A strong interview or viva answer for nestjs environment variables .env must go beyond a one-line definition. Interviewers evaluating BCA, MCA, B.Tech, and self-taught backend developers reward answers that combine a precise definition, a clear working explanation, a real-world example, and a conclusion that highlights why it matters in production Node.js applications. Use the four-point framework below when answering under time pressure.

  • Definition point: Environment variable: A key-value pair available to a running process, provided by the operating system or a process manager, used to configure behavior without changing code.
  • Working point: Write a properly formatted .env file for a NestJS project.
  • Example point: Every professional NestJS project's README typically includes a step instructing new developers to copy .env.example to .env and fill in their own local values before running the application for the first time.
  • Conclusion point: A .env file is simply a convenient way to define environment variables for local development without setting them manually every time.

How to Answer This in a Technical Interview

  1. Give a two-to-three sentence definition using correct NestJS and Node.js terminology.
  2. Add one specific example drawn from a real backend scenario such as an e-commerce, fintech, or SaaS API.
  3. Mention the request lifecycle stage this concept operates at (pipe, guard, middleware, filter, interceptor) since interviewers often test whether you know the execution order.
  4. Close with one benefit, trade-off, or production use case.
  5. Avoid vague answers like "it just validates stuff" — interviewers filter these out immediately.

Practical Scenario

Imagine you are hardening a production API for a SaaS product, similar to systems used at companies like Razorpay, Freshworks, or Postman. Every lesson in this module maps directly to a decision you will make while making that backend secure, predictable, and resilient to bad input: validating what comes in, transforming it safely, catching failures gracefully, and protecting routes from unauthorized access.

NestJS Environment Variables .env: Architecture and Flow Diagram

Visualize the flow of an environment variable from file to code:

[.env file: DATABASE_URL=postgresql://localhost:5432/mydb] --> [dotenv/ConfigModule reads file at startup] --> [process.env.DATABASE_URL now holds this value] --> [ConfigService.get('DATABASE_URL') retrieves it safely in your NestJS code]

Add a note: '.env is excluded from Git via .gitignore; .env.example (with placeholder values) is committed instead.'

NestJS Environment Variables .env: File Reference Table

FileContains Real Secrets?Committed to Git?Purpose
.envYesNo (excluded via .gitignore)Actual local configuration and secrets
.env.exampleNo, placeholders onlyYesTemplate showing which variables are required
.env.developmentYes (dev-specific)NoConfiguration specific to local development
.env.productionYes (prod-specific)No (managed via deployment platform)Configuration specific to the live production environment

NestJS Environment Variables .env: NestJS Code Example

# .env — actual local configuration (never committed to Git)
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=devpassword123
JWT_SECRET=local-dev-secret-key
PORT=3000
NODE_ENV=development

# .env.example — committed template with placeholder values
DATABASE_HOST=
DATABASE_PORT=5432
DATABASE_USER=
DATABASE_PASSWORD=
JWT_SECRET=
PORT=3000
NODE_ENV=development

# .gitignore — ensures the real .env file is never tracked by Git
node_modules/
dist/
.env
.env.local
.env.*.local

# Verifying environment variables load correctly (quick manual check)
# Add temporarily inside main.ts for a sanity check, then remove:
# console.log('Loaded PORT from env:', process.env.PORT);

The .env file contains real, working local development values, including a placeholder password and JWT secret that would obviously differ in a real production environment. The .env.example file mirrors the exact same variable names but with empty or generic placeholder values, giving any new developer joining the project a clear, safe template to copy into their own local .env file. The .gitignore file explicitly excludes .env (and variants like .env.local) from version control, while still allowing .env.example to be tracked normally since it contains no real secrets. The commented-out console.log line shows a simple, temporary sanity check developers commonly use to confirm environment variables are actually loading as expected during initial project setup.

Real-World NestJS Environment Variables .env Industry Examples

  • Every professional NestJS project's README typically includes a step instructing new developers to copy .env.example to .env and fill in their own local values before running the application for the first time.
  • Companies using CI/CD pipelines inject environment variables directly through their pipeline's secret management interface (GitHub Actions secrets, GitLab CI variables) rather than committing any environment file, even for automated builds.
  • Cloud platforms like AWS, Heroku, and Vercel provide their own dashboard-based environment variable configuration, which effectively replaces a literal .env file in production, since the platform itself securely injects these values into the running process.
  • Security audits and automated secret-scanning tools (like GitHub's secret scanning) specifically look for accidentally committed .env files or hardcoded API keys, a mistake serious enough that many companies have dedicated tooling just to catch it before it happens.

NestJS Environment Variables .env Interview Questions and Answers

Q1. What is an environment variable and why is it useful for configuring applications?

Short answer: An environment variable is a named value available to a running process, provided by the operating system or process manager. It is useful for configuration because it allows the exact same application code to behave differently across environments, such as using a different database URL in development versus production, without any code changes.

Detailed explanation: At the operating system level, an environment variable is simply a named value available to any running process, historically used for things like PATH (which directories contain executable programs) or HOME (a user's home directory). Node.js applications, including NestJS applications, access these variables through the global process.env object, where every environment variable appears as a string property. Manually setting environment variables directly in your terminal every time you start a development server is tedious and error-prone, especially as the number of required variables grows. This is the exact problem a .env file solves: it lets you define all your environment variables in a single, plain text file at your project's root, using a simple KEY=value syntax, one variable per line, such as DATABASE_URL=postgresql://localhost:5432/mydb or PORT=3000. When your NestJS application starts, either through @nestjs/config's ConfigModule or a plain dotenv.config() call, this file is read and its contents are loaded into process.env, exactly as if you had set them manually in your terminal. A critical, non-negotiable practice is excluding your .env file from version control using .gitignore. Since .env files commonly contain sensitive values like database passwords, API keys, and JWT signing secrets, accidentally committing this file to a public (or even private) Git repository can expose these secrets to anyone with access to the repository's history, a mistake that has caused real security incidents at real companies. The standard convention is committing a .env.example file instead, listing every required variable name with a placeholder or empty value, giving other developers on the team a clear template to create their own local .env file from, without ever exposing actual secret values. As a project matures beyond local development, it typically needs distinct configuration for different environments: a development .env pointing to a local database, a staging .env pointing to a staging environment's resources, and a production .env (usually managed through a deployment platform's secret management system rather than a literal file) pointing to live production infrastructure. Many teams manage this using separate files like .env.development and .env.production, loaded conditionally based on the current NODE_ENV value, ensuring the exact same codebase behaves correctly and safely across every stage of the deployment pipeline without a single line of source code needing to change.

Practical example: Every professional NestJS project's README typically includes a step instructing new developers to copy .env.example to .env and fill in their own local values before running the application for the first time.

Interview tip: Environment variables are OS/process-level key-value pairs, accessed in Node.js via process.env.

Revision hook: A .env file is simply a convenient way to define environment variables for local development without setting them manually every time.

Q2. Why should a .env file never be committed to version control?

Short answer: A .env file typically contains sensitive information such as database passwords, API keys, and secret signing keys. Committing it to version control, especially a public repository, would expose these secrets to anyone with access to the repository, creating a serious and often costly security vulnerability.

Detailed explanation: The .env file contains real, working local development values, including a placeholder password and JWT secret that would obviously differ in a real production environment. The .env.example file mirrors the exact same variable names but with empty or generic placeholder values, giving any new developer joining the project a clear, safe template to copy into their own local .env file. The .gitignore file explicitly excludes .env (and variants like .env.local) from version control, while still allowing .env.example to be tracked normally since it contains no real secrets. The commented-out console.log line shows a simple, temporary sanity check developers commonly use to confirm environment variables are actually loading as expected during initial project setup.

Practical example: Companies using CI/CD pipelines inject environment variables directly through their pipeline's secret management interface (GitHub Actions secrets, GitLab CI variables) rather than committing any environment file, even for automated builds.

Interview tip: dotenv is the library that loads a .env file's contents into process.env; @nestjs/config uses it internally.

Revision hook: Never committing a real .env file to version control is one of the most basic, non-negotiable security practices in professional backend development.

Q3. What is the purpose of a .env.example file?

Short answer: A .env.example file serves as a safe, committed template listing every environment variable a project requires, using placeholder or empty values instead of real secrets. It allows new developers to quickly understand what configuration is needed and create their own local .env file without exposing or needing access to actual production secrets.

Detailed explanation: Environment variables are key-value pairs available to a running process, and a .env file provides a simple, convenient way to define them for a NestJS project without setting them manually in a terminal every time. Loaded via the dotenv library, either directly or through @nestjs/config's ConfigModule covered in the previous lesson, these values become accessible through Node.js's process.env object. Because .env files commonly contain sensitive secrets like database passwords and API keys, they must always be excluded from version control using .gitignore, with a safe, placeholder-only .env.example file committed instead to guide other developers. As projects grow to span multiple environments, development, staging, and production typically rely on separate configuration sources, whether through distinct environment files or a hosting platform's own secret management system, ensuring the same codebase runs correctly and securely everywhere.

Practical example: Cloud platforms like AWS, Heroku, and Vercel provide their own dashboard-based environment variable configuration, which effectively replaces a literal .env file in production, since the platform itself securely injects these values into the running process.

Interview tip: .env must be excluded via .gitignore; .env.example (with placeholders only) should be committed instead.

Revision hook: A well-maintained .env.example file is a small courtesy that saves significant onboarding time for every new developer on a team.

Q4. How would you manage different environment variables for development, staging, and production in a NestJS project?

Short answer: You would typically use separate environment files, such as .env.development and .env.production, loaded conditionally based on the current NODE_ENV value, or rely on your deployment platform's own environment variable management system for staging and production, while keeping only local development values in an actual .env file on developer machines.

Detailed explanation: At the operating system level, an environment variable is simply a named value available to any running process, historically used for things like PATH (which directories contain executable programs) or HOME (a user's home directory). Node.js applications, including NestJS applications, access these variables through the global process.env object, where every environment variable appears as a string property. Manually setting environment variables directly in your terminal every time you start a development server is tedious and error-prone, especially as the number of required variables grows. This is the exact problem a .env file solves: it lets you define all your environment variables in a single, plain text file at your project's root, using a simple KEY=value syntax, one variable per line, such as DATABASE_URL=postgresql://localhost:5432/mydb or PORT=3000. When your NestJS application starts, either through @nestjs/config's ConfigModule or a plain dotenv.config() call, this file is read and its contents are loaded into process.env, exactly as if you had set them manually in your terminal. A critical, non-negotiable practice is excluding your .env file from version control using .gitignore. Since .env files commonly contain sensitive values like database passwords, API keys, and JWT signing secrets, accidentally committing this file to a public (or even private) Git repository can expose these secrets to anyone with access to the repository's history, a mistake that has caused real security incidents at real companies. The standard convention is committing a .env.example file instead, listing every required variable name with a placeholder or empty value, giving other developers on the team a clear template to create their own local .env file from, without ever exposing actual secret values. As a project matures beyond local development, it typically needs distinct configuration for different environments: a development .env pointing to a local database, a staging .env pointing to a staging environment's resources, and a production .env (usually managed through a deployment platform's secret management system rather than a literal file) pointing to live production infrastructure. Many teams manage this using separate files like .env.development and .env.production, loaded conditionally based on the current NODE_ENV value, ensuring the exact same codebase behaves correctly and safely across every stage of the deployment pipeline without a single line of source code needing to change.

Practical example: Security audits and automated secret-scanning tools (like GitHub's secret scanning) specifically look for accidentally committed .env files or hardcoded API keys, a mistake serious enough that many companies have dedicated tooling just to catch it before it happens.

Interview tip: Different environments (development, staging, production) typically use separate environment configuration sources.

Revision hook: Production environments should rely on a hosting platform's secure secret management rather than a literal .env file whenever possible.

NestJS Environment Variables .env MCQs and Practice Questions

1. What Node.js library does NestJS's configuration system typically use to read .env files?

  1. axios
  2. dotenv
  3. express
  4. mongoose

Answer: B. dotenv

Explanation: dotenv is the standard Node.js library used to parse a .env file's contents and load them into the process.env object, and it is used internally by @nestjs/config's ConfigModule.

Concept link: Environment variables are OS/process-level key-value pairs, accessed in Node.js via process.env.

Why this matters: A .env file is simply a convenient way to define environment variables for local development without setting them manually every time.

2. Where should a .env file containing real secrets typically be listed to prevent it from being committed to Git?

  1. package.json
  2. tsconfig.json
  3. .gitignore
  4. nest-cli.json

Answer: C. .gitignore

Explanation: .gitignore is the file used to tell Git which files and folders to ignore, and a project's real .env file should always be listed here to prevent sensitive secrets from being accidentally committed.

Concept link: dotenv is the library that loads a .env file's contents into process.env; @nestjs/config uses it internally.

Why this matters: Never committing a real .env file to version control is one of the most basic, non-negotiable security practices in professional backend development.

3. What is the main purpose of committing a .env.example file to version control?

  1. To store real production secrets safely
  2. To provide a template of required environment variables with placeholder values
  3. To replace the need for a .env file entirely
  4. To automatically deploy the application

Answer: B. To provide a template of required environment variables with placeholder values

Explanation: .env.example gives other developers a clear, safe reference showing which environment variables a project needs, without exposing any actual secret values, since it only contains placeholders.

Concept link: .env must be excluded via .gitignore; .env.example (with placeholders only) should be committed instead.

Why this matters: A well-maintained .env.example file is a small courtesy that saves significant onboarding time for every new developer on a team.

4. How does a Node.js application access a value loaded from a .env file?

  1. Through a global 'config' object
  2. Through process.env
  3. Through require('.env')
  4. Through import env from 'nestjs'

Answer: B. Through process.env

Explanation: Once a .env file's contents are loaded by dotenv (directly or through @nestjs/config), each variable becomes accessible as a string property on Node.js's global process.env object.

Concept link: Different environments (development, staging, production) typically use separate environment configuration sources.

Why this matters: Production environments should rely on a hosting platform's secure secret management rather than a literal .env file whenever possible.

Common NestJS Environment Variables .env Mistakes to Avoid

  • Accidentally committing a real .env file to Git before adding it to .gitignore, exposing secrets even if it's removed in a later commit, since Git history still retains it.
  • Forgetting to create or update .env.example when adding new required environment variables, leaving other developers on the team unaware they need to set a new value.
  • Storing production secrets directly in a .env file on a shared server instead of using a proper secret management system provided by the hosting platform.
  • Using inconsistent casing or naming conventions for environment variables across a project, making it harder to remember exact variable names when accessing them via process.env or ConfigService.

NestJS Environment Variables .env: Interview Notes and Exam Tips

  • Environment variables are OS/process-level key-value pairs, accessed in Node.js via process.env.
  • dotenv is the library that loads a .env file's contents into process.env; @nestjs/config uses it internally.
  • .env must be excluded via .gitignore; .env.example (with placeholders only) should be committed instead.
  • Different environments (development, staging, production) typically use separate environment configuration sources.

Key NestJS Environment Variables .env Takeaways

  • A .env file is simply a convenient way to define environment variables for local development without setting them manually every time.
  • Never committing a real .env file to version control is one of the most basic, non-negotiable security practices in professional backend development.
  • A well-maintained .env.example file is a small courtesy that saves significant onboarding time for every new developer on a team.
  • Production environments should rely on a hosting platform's secure secret management rather than a literal .env file whenever possible.

NestJS Environment Variables .env: Summary

Environment variables are key-value pairs available to a running process, and a .env file provides a simple, convenient way to define them for a NestJS project without setting them manually in a terminal every time. Loaded via the dotenv library, either directly or through @nestjs/config's ConfigModule covered in the previous lesson, these values become accessible through Node.js's process.env object. Because .env files commonly contain sensitive secrets like database passwords and API keys, they must always be excluded from version control using .gitignore, with a safe, placeholder-only .env.example file committed instead to guide other developers. As projects grow to span multiple environments, development, staging, and production typically rely on separate configuration sources, whether through distinct environment files or a hosting platform's own secret management system, ensuring the same codebase runs correctly and securely everywhere.

Frequently Asked Questions

No, @nestjs/config includes dotenv as an internal dependency and uses it automatically when ConfigModule.forRoot() is called, so you do not need to install or configure dotenv separately in a standard NestJS project using @nestjs/config. In interviews, tie this back to: Environment variables are OS/process-level key-value pairs, accessed in Node.js via process.env. In real applications, consider this example: Every professional NestJS project's README typically includes a step instructing new developers to copy .env.example to .env and fill in their own local values before running the application for the first time. Key revision takeaway: A .env file is simply a convenient way to define environment variables for local development without setting them manually every time.

Any environment variables your application expects will simply be undefined in process.env, which can cause your application to fail to start (if validation is configured, as covered in the previous lesson) or behave unexpectedly if your code doesn't handle missing configuration gracefully. In interviews, tie this back to: dotenv is the library that loads a .env file's contents into process.env; @nestjs/config uses it internally. In real applications, consider this example: Companies using CI/CD pipelines inject environment variables directly through their pipeline's secret management interface (GitHub Actions secrets, GitLab CI variables) rather than committing any environment file, even for automated builds. Key revision takeaway: Never committing a real .env file to version control is one of the most basic, non-negotiable security practices in professional backend development.

Yes, dotenv supports quoted values, which is particularly useful when a value contains spaces or special characters. Both single and double quotes are generally supported, and dotenv will strip the surrounding quotes when loading the value into process.env. In interviews, tie this back to: .env must be excluded via .gitignore; .env.example (with placeholders only) should be committed instead. In real applications, consider this example: Cloud platforms like AWS, Heroku, and Vercel provide their own dashboard-based environment variable configuration, which effectively replaces a literal .env file in production, since the platform itself securely injects these values into the running process. Key revision takeaway: A well-maintained .env.example file is a small courtesy that saves significant onboarding time for every new developer on a team.

While technically possible, most professional teams prefer using their cloud platform's dedicated secret management system (such as AWS Secrets Manager, environment variables configured directly in a hosting dashboard, or Kubernetes secrets) rather than a literal .env file sitting on a production server's file system, for better security and auditability. In interviews, tie this back to: Different environments (development, staging, production) typically use separate environment configuration sources. In real applications, consider this example: Security audits and automated secret-scanning tools (like GitHub's secret scanning) specifically look for accidentally committed .env files or hardcoded API keys, a mistake serious enough that many companies have dedicated tooling just to catch it before it happens. Key revision takeaway: Production environments should rely on a hosting platform's secure secret management rather than a literal .env file whenever possible.

A common convention is using .env for default/local values, and environment-specific overrides like .env.development, .env.staging, and .env.production, often loaded conditionally based on the NODE_ENV variable, though exact conventions can vary by team and deployment platform. In interviews, tie this back to: Environment variables are OS/process-level key-value pairs, accessed in Node.js via process.env. In real applications, consider this example: Every professional NestJS project's README typically includes a step instructing new developers to copy .env.example to .env and fill in their own local values before running the application for the first time. Key revision takeaway: A .env file is simply a convenient way to define environment variables for local development without setting them manually every time.

Leaving values empty (or using an obviously fake placeholder) in .env.example intentionally avoids exposing any real secret, while still documenting the variable's name so a new developer knows exactly which environment variables they need to obtain and set in their own local .env file. In interviews, tie this back to: dotenv is the library that loads a .env file's contents into process.env; @nestjs/config uses it internally. In real applications, consider this example: Companies using CI/CD pipelines inject environment variables directly through their pipeline's secret management interface (GitHub Actions secrets, GitLab CI variables) rather than committing any environment file, even for automated builds. Key revision takeaway: Never committing a real .env file to version control is one of the most basic, non-negotiable security practices in professional backend development.