The Hidden Truth About Booleans in .env Files: Why 'false' Is Still Truthy in JavaScript

The Hidden Truth About Booleans in .env Files: Why 'false' Is Still Truthy in JavaScript

posted 3 min read

Understanding Environment Variables in Node.js

In Node.js (and frameworks like NestJS), environment variables, typically managed through .env files and accessed using process.env, are always strings. This subtle fact can introduce unexpected bugs, especially when you're expecting a boolean (true or false) but get a string ("true" or "false").

Real-World Example in a Node.js/NestJS Project

Suppose you have a .env file like this:

DB_SYNCHRONIZE=false
DB_LOGGING=true

And in your configuration code:

database: {
  synchronize: process.env.DB_SYNCHRONIZE,
  logging: process.env.DB_LOGGING,
}

You expect synchronize to be false and logging to be true.
But in reality, both will be truthy because they are non-empty strings!

The Bug in Action
Why is this a problem?

console.log(process.env.DB_SYNCHRONIZE); // "false" (string)
if (process.env.DB_SYNCHRONIZE) {
  console.log("This runs!"); // This will run, even though you set it to "false"
}

This is because in JavaScript:

  • "false" (string) is truthy
  • Only "", 0, null, undefined, and false (boolean) are falsy
Boolean("false"); // true
Boolean("true");  // true
Boolean("")       // false

So, if you pass process.env.DB_SYNCHRONIZE directly to a library expecting a boolean, it will act as true!

So "false" (a non-empty string) is truthy, and the if block runs, even though logically you set it to false!

This behavior can lead to critical misconfigurations in production environments. For example, enabling logging, enabling DB synchronization (which drops and recreates tables in some ORMs), or accidentally exposing debug features.

Always convert environment variable strings to booleans explicitly.

The Correct Approach: Explicit Type Conversion

Boolean Conversion Pattern

Always parse environment variables to their expected types before use.

const synchronize = process.env.DB_SYNCHRONIZE === 'true';
const logging = process.env.DB_LOGGING === 'true';

This way:

  • 'true' === 'true'true
  • 'false' === 'true'false

You now get predictable, safe boolean values.

Optional Utility Function

For larger projects, it's wise to create a helper:

function toBool(value: string | undefined): boolean {
  return value?.toLowerCase() === 'true';
}

const synchronize = toBool(process.env.DB_SYNCHRONIZE);
const logging = toBool(process.env.DB_LOGGING);

Pro Tip: Use a Config Validation Library

Frameworks like NestJS recommend using a validation layer (e.g., with Joi or zod) to validate and transform config values at startup.

Example using Joi:

const configSchema = Joi.object({
  DB_SYNCHRONIZE: Joi.boolean().default(false),
  DB_LOGGING: Joi.boolean().default(false),
});

Real-Life Pitfall: When "false" Isn’t Really False

This isn’t just theory, I ran into this issue myself while working on a NestJS project using TypeORM.

I had this in my .env:

DB_SYNCHRONIZE=false

And my config looked like:

synchronize: process.env.DB_SYNCHRONIZE,

I assumed this would disable TypeORM’s automatic schema synchronization, since I planned to use migrations instead.

But when I started the app, the tables were still being created. Then, when I tried to generate a migration:

typeorm migration:generate -n AddNewFields

I kept seeing:

No changes in database schema were found - cannot generate a migration.

It was confusing, until I logged the value of process.env.DB_SYNCHRONIZE and saw:

console.log(typeof process.env.DB_SYNCHRONIZE); // string
console.log(process.env.DB_SYNCHRONIZE);        // "false"

That string "false" is truthy, so synchronize: "false" is effectively treated as true in JavaScript. TypeORM was happily syncing the schema on every run, and by the time I tried to run the migration generator, there were no changes left to detect.

Final Thoughts

Misinterpreting environment variables is one of those bugs that can sneak into production unnoticed until something critical misbehaves. In systems where flags control behavior like syncing databases, enabling debug logs, or toggling features, treating "false" as a boolean without conversion can be dangerous.

Always treat process.env values as untrusted strings and explicitly cast them to the types your logic expects. Doing this upfront helps you avoid fragile assumptions and keeps your config layer predictable.

If you read this far, tweet to the author to show them you care. Tweet a Thanks
0 votes
0 votes

More Posts

PHP vs Node.js in 2025: The Shocking Truth About Performance

Cloud Guru - Jul 1

Advanced Strategies: How to Implement the Strategy Pattern in Your NestJS Projects

fredydlemus - Jan 29

Why NestJS is the Future of Scalable Backend Development and Why Angular Developers Love NestJS

Sunny - Sep 27

Why NestJS Is The New Gold Standard For Node Backend Development

Rayen Mabrouk - Jan 14

Grasping the different Solana clusters—Devnet, Testnet, and Mainnet—is essential for efficient development.

adewumi israel - Feb 11
chevron_left