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.

0 votes
0 votes

More Posts

Bridging the Silence: Why Objective Data Outperforms Subjective Health Reports in Elderly Care

Huifer - Jan 27

The End of Data Export: Why the Cloud is a Compliance Trap

Pocket Portfolio - Apr 6

The Privacy Gap: Why sending financial ledgers to OpenAI is broken

Pocket Portfolio - Feb 23

Beyond the 98.6°F Myth: Defining Personal Baselines in Health Management

Huifer - Feb 2

Your App Feels Smart, So Why Do Users Still Leave?

kajolshah - Feb 2
chevron_left

Related Jobs

View all jobs →

Commenters (This Week)

6 comments
4 comments
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!