Skip to content

v5: present-but-empty .env keys (KEY=) are dropped and reported as "not defined" #603

Description

@GeorgianSorinMaxim

Summary

Since 4.0.0 (still in 5.0.0), a key that is present in .env with an empty value (API_KEY=) is treated as if it were missing. With safe: true and allowUndefined: false the build fails:

"API_KEY" is not defined in .env

In 3.4.11 the same file worked: the import compiled to "".

Cause

index.js (5.0.0, lines 127–129) builds the final env object with undefObjectAssign({}, fileEnv):

env = (options.safe)
  ? safeObjectAssign(undefObjectAssign({}, fileEnv), dotenvTemporary, modeExceptions)
  : undefObjectAssign(undefObjectAssign({}, fileEnv), dotenvTemporary)

undefObjectAssign copies a key only when its value is truthy, so every empty-string value is dropped before the Object.hasOwn(env, importedId) check runs. dotenv.parse itself does return the key with "".

In 3.4.11 the overlays (.env.<mode>, .env.local, …) were merged into the parsed main-file object, so a key present in the main .env with an empty value stayed defined:

env = (options.safe) ? safeObjectAssign(undefObjectAssign(undefObjectAssign(undefObjectAssign(parsed, modeParsed), localParsed), modeLocalParsed), dotenvTemporary, [...])

The extra undefObjectAssign({}, fileEnv) step is what changed the behaviour.

Reproduction

.env:

API_KEY=

Babel config:

['module:react-native-dotenv', { moduleName: '@env', safe: true, allowUndefined: false }]

Source:

import { API_KEY } from '@env';
export const a = API_KEY;
  • 3.4.11 → export const a = "";
  • 5.0.0 → "API_KEY" is not defined in .env

Expected

A key that exists in the file, even with an empty value, is defined (as the empty string). Leaving an optional secret blank in local development while CI fills it in is a common pattern, and the safe mode error message is misleading here because the key is defined.

Suggested fix

Keep the fresh object but do not re-filter it:

env = (options.safe)
  ? safeObjectAssign(Object.assign({}, fileEnv), dotenvTemporary, modeExceptions)
  : Object.assign(Object.assign({}, fileEnv), dotenvTemporary)

safeObjectAssign still refuses to overwrite with a falsy host value, and dotenvTemporary is already filtered, so nothing else changes. Happy to open a PR if this is the preferred direction.

Versions: react-native-dotenv 5.0.0, dotenv 18.0.3, @babel/core 7.28.6, Node 24.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions