Skip to content

fix: improve boolean env var coercion and add NO_ prefix negation support#523

Open
kaigritun wants to merge 1 commit intoyargs:mainfrom
kaigritun:fix/env-boolean-coercion
Open

fix: improve boolean env var coercion and add NO_ prefix negation support#523
kaigritun wants to merge 1 commit intoyargs:mainfrom
kaigritun:fix/env-boolean-coercion

Conversation

@kaigritun
Copy link

Summary

Fixes yargs/yargs#2501

This PR addresses two related issues with how boolean options are handled when set via environment variables:

Issue 1: Boolean string coercion only accepts 'true'

Previously, when a boolean option was set via environment variable, only the exact string 'true' was recognized as truthy. This caused unexpected behavior:

MY_CMD_DO_THING=1     # became false (expected: true)
MY_CMD_DO_THING=yes   # became false (expected: true)
MY_CMD_DO_THING=true  # worked correctly

Fix: Boolean string coercion now accepts common truthy/falsy values:

  • Truthy: 'true', '1', 'yes', 'on'
  • Falsy: 'false', '0', 'no', 'off'

Issue 2: NO_ prefix not recognized for boolean negation

The CLI supports --no-doThing for boolean negation, but the equivalent env var MY_CMD_NO_DO_THING was not recognized as negation - it was treated as a separate option.

Fix: Environment variables with NO_ prefix (after the env prefix) are now treated as boolean negation:

  • MY_CMD_NO_DO_THING=truedoThing: false
  • MY_CMD_NO_DO_THING=falsedoThing: true (double negation)

The implementation respects the 'negation-prefix' and 'boolean-negation' configuration options.

Testing

Added 7 new test cases covering:

  • Boolean env var with '1' value
  • Boolean env var with '0' value
  • Boolean env var with 'yes' value
  • Boolean env var with 'no' value
  • NO_ prefix with 'true' value
  • NO_ prefix with '1' value
  • NO_ prefix with 'false' value (double negation)

All existing tests continue to pass (369 total).

…port

Fixes yargs/yargs#2501

Two issues addressed:

1. Boolean string coercion now accepts common truthy/falsy values:
   - 'true', '1', 'yes', 'on' → true
   - 'false', '0', 'no', 'off' → false
   Previously only 'true' was recognized as truthy.

2. Environment variables with NO_ prefix are now treated as boolean
   negation (consistent with --no-* CLI behavior):
   - MY_APP_NO_DO_THING=true → doThing: false
   - MY_APP_NO_DO_THING=false → doThing: true (double negation)

The NO_ prefix respects the 'negation-prefix' and 'boolean-negation'
configuration options.
@shadowspawn
Copy link
Member

Interesting. I hadn't commented on what I thought behaviour should be in yargs/yargs#2501 (comment), just confirmed how it currently worked.

I have been doing some research. For NO_ negation...

I do not think we should support NO_ negation. I do see the appeal for parity with --no, but boolean options are detected by their presence whereas we are already parsing environment variable values. We have one option --foo which can be negated with --no-foo. We have one environment variable FOO which can be negated with FOO=false. Negated environment variables are reasonably rare in practice (with legacy NO_COLOR an example).

Common use of options:

mycmd --print
mycmd --no-print

Common (and clear) use of environment variables which use values:

MY_CMD_PRINT=true
MY_CMD_PRINT=false

Negated variables with a value are less clear. (I personally avoid creating variables that start with a "no".)

MY_CMD_NO_PRINT=true
MY_CMD_NO_PRINT=false # yuck!

And lastly, adding a negation introduces a potential conflict, as now two variables instead of one. Which one wins? On command-line the last one wins, but that does not work for environment variables.

MY_CMD_PRINT=true
MY_CMD_NO_PRINT=true

@shadowspawn
Copy link
Member

I think the 1/0 recognition for environment variables covers a common usage and expectation. I am not so keen on the yes/no and off/on. I have not come across those often in the wild. Are you aware of utilities that support those, or where they are commonly used?

@kaigritun
Copy link
Author

Good question! The 1/0 is definitely the most common. For yes/no and on/off:

  • yes/no: Common in interactive prompts (e.g., npm init style tools) and some config systems like Apache httpd (KeepAlive On/Off), MySQL (query_cache_type=ON)
  • on/off: Used in git config (core.autocrlf=true but also accepts on), PHP (display_errors = On), and various INI-style configs

That said, if you'd prefer to keep it minimal and just support 1/0 (plus the existing true/false), I'm happy to trim it down. The core fix for the coverage issue is separate from the extended value recognition.

Comment on lines +628 to +629
// For other strings, treat non-empty as truthy (backwards compat edge case)
val = val === 'true'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// For other strings, treat non-empty as truthy (backwards compat edge case)
val = val === 'true'
// For other strings, treat as false (backwards compat edge case)
val = false

}
}

function processValue (key: string, val: any, shouldStripQuotes: boolean) {
Copy link
Member

@shadowspawn shadowspawn Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making changes in processValue affects more than just environment variables. I think that is potentially ok, somewhat of an edge case, and maintains compatibility between ENV and other cases.

I think it just affects --foo=VALUE when foo is boolean.

@shadowspawn
Copy link
Member

shadowspawn commented Feb 8, 2026

That said, if you'd prefer to keep it minimal and just support 1/0 (plus the existing true/false), I'm happy to trim it down.

Thanks for examples. Keep them in for now, and I'll keep thinking. 🤔 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Boolean arguments read via environment variables do not support no-prefixed variants

2 participants