npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-dotenv

v4.1.1

Published

Load .env into React Native with import statements. A Babel plugin that inlines environment variables at build time.

Readme

react-native-dotenv NPM version downloads

Load .env into React Native with import statements. A Babel plugin that inlines your environment variables at build time — with multi-environment support.

 

Usage

Install it.

npm install react-native-dotenv --save-dev

Add it to your Babel config:

// babel.config.js
module.exports = function (api) {
  api.cache(false)
  return {
    plugins: [
      ['module:react-native-dotenv']
    ]
  }
}

Create a .env file in the root of your project:

# .env
HELLO="Dotenv"
API_URL=https://api.example.org

Import your environment variables:

// App.js
import { HELLO, API_URL } from '@env'

console.log(`Hello ${HELLO}`)
fetch(`${API_URL}/users`)

That's it. Your environment variables from .env are available via @env.

On transform you'll see a message on stderr (same style as dotenv):

◇ injected env (2) from .env

Metro may prefix worker logs with |. Expo also prints its own env: load .env line — that is Expo's built-in loader, not this plugin.

Set quiet: true in the plugin options to suppress the ◇ injected env message.

 

Advanced

Override which environment variable selects the mode file (separate from NODE_ENV). Metro can overwrite the test environment even if you specify a config, so this gives you a dedicated override.

// package.json
{
  "scripts": {
    "start:staging": "APP_ENV=staging npx react-native start"
  }
}

The above example would use the .env.staging file.

To use your own name:

{
  "plugins": [
    ["module:react-native-dotenv", {
      "envName": "MY_ENV"
    }]
  ]
}
// package.json
{
  "scripts": {
    "start:staging": "MY_ENV=staging npx react-native start"
  }
}

Note: if you're using APP_ENV (or envName), you cannot use development nor production as values, and you should avoid having a .env.development or .env.production. This is a Babel and Node thing that I have little control over unfortunately and is consistent with many other platforms that have an override option, like Gatsby. If you want to use development and production, you should not use APP_ENV (or envName), but rather the built-in NODE_ENV=development or NODE_ENV=production or you can just use debug vs release modes. It actually does compile but only for the start command so it is up to you but then you have to run react-native start every time you change the values.

The module name used in import statements.

import { HELLO } from '@env'

For TypeScript or Next.js it is often advised to set moduleName to react-native-dotenv.

{
  "plugins": [
    ["module:react-native-dotenv", {
      "moduleName": "react-native-dotenv"
    }]
  ]
}

Path to the base env file.

{
  "plugins": [
    ["module:react-native-dotenv", {
      "path": ".env"
    }]
  ]
}

Limit imports to only these env variable names.

{
  "plugins": [
    ["module:react-native-dotenv", {
      "allowlist": [
        "HELLO",
        "API_URL"
      ]
    }]
  ]
}

Prevent these env variable names from being imported.

{
  "plugins": [
    ["module:react-native-dotenv", {
      "blocklist": [
        "GITHUB_TOKEN"
      ]
    }]
  ]
}

Only allow variables defined in your .env files. Host environment variables can still override values for those same keys at build time, but keys that exist only in the environment (and not in .env) are not imported.

{
  "plugins": [
    ["module:react-native-dotenv", {
      "safe": true
    }]
  ]
}

When using safe mode, it's highly recommended to set allowUndefined to false.

Allow importing undefined variables; their value will be undefined.

{
  "plugins": [
    ["module:react-native-dotenv", {
      "allowUndefined": true
    }]
  ]
}
import { UNDEFINED_VAR } from '@env'

console.log(UNDEFINED_VAR === undefined) // true

When set to false, an error will be thrown.

Also print the active dotenv mode to stderr while transforming.

{
  "plugins": [
    ["module:react-native-dotenv", {
      "verbose": true
    }]
  ]
}

Suppress the stderr inject message (◇ injected env (N) from .env).

{
  "plugins": [
    ["module:react-native-dotenv", {
      "quiet": true
    }]
  ]
}

You can also use process.env — the plugin inlines matching keys at build time the same way.

console.log(`Hello ${process.env.HELLO}`)
fetch(`${process.env.API_URL}/users`)

process.env.X is only inlined when X is in your .env files (plus NODE_ENV / BABEL_ENV / envName). That keeps build-tooling noise out of the bundle without special-casing tool names.

For host/CI-only values, use @env imports — or put the key in .env and let CI override the value.

Expo has built-in environment variable support. Use this plugin when you want @env imports or multi-env files (e.g. .env.staging via APP_ENV).

// babel.config.js
module.exports = function (api) {
  api.cache(false)
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      ['module:react-native-dotenv']
    ]
  }
}
# .env
HELLO="Universe"
// app/index.tsx
import { HELLO } from '@env'
import { Text } from 'react-native'

export default function HomeScreen() {
  return <Text>Hello {HELLO}</Text>
}

Then start with a clean Metro cache: npx expo start --clear.

This package now supports environment specific variables. This means you may now import environment variables from multiple files, i.e. .env, .env.development, .env.production, and .env.test. This is based on dotenv-flow.

Note: it is not recommended that you commit any sensitive information in .env file to code in case your git repo is exposed. The best practice is to put a .env.template or .env.development.template that contains dummy values so other developers know what to configure. Then add your .env and .env.development to .gitignore. You can also keep sensitive keys in a separate .env.local (and respective .env.local.template) in .gitignore and you can use your other .env files for non-sensitive config.

If you are publishing your apps on an auto-publishing platform like EAS (Expo Application Services), make sure to put your secrets on the platform dashboard directly. If you are wondering what environment the platforms choose it is likely .env.production (not .env.prod) and there is likely no way to change this.

The base set of variables will be .env and the environment-specific variables will overwrite them.

The variables will automatically be pulled from the appropriate environment and development is the default. The choice of environment is based on your Babel environment first and if that value is not set, your NPM environment, which should actually be the same, but this makes it more robust.

In general, Release is production and Debug is development.

To choose, setup your scripts with NODE_ENV for each environment

// package.json
{
  "scripts": {
    "start:development": "NODE_ENV=development npx react-native start",
    "start:production": "NODE_ENV=production npx react-native start"
  }
}

Prefer Zod to validate your env and infer types — no hand-written env.d.ts needed.

import { z } from 'zod'

export const env = z.object({
  HELLO: z.string().min(1),
  API_URL: z.string().url()
}).parse({
  HELLO: process.env.HELLO,
  API_URL: process.env.API_URL
})

console.log(`Hello ${env.HELLO}`)
fetch(`${env.API_URL}/users`)

env is fully typed from the schema. If a value is missing or invalid, Zod throws at startup instead of failing later in production.

If you are not familiar with how dotenv or Babel work, make sure to read the following reference materials:

How this works

This Babel plugin processes your .env files and your environment variables and replaces the references to the environment variables in your code before it runs. This is because the environment variables will no longer be accessible once the React Native engine generates the app outputs.

When using with babel-loader with caching enabled you will run into issues where environment changes won’t be picked up. This is due to the fact that babel-loader computes a cacheIdentifier that does not take your .env file(s) into account. The good news is that a recent update has fixed this problem as long as you're using a new version of Babel. Many react native libraries have not updated their Babel version yet so to force the version, add in your package.json:

"resolutions": {
  "@babel/core": "^7.20.2",
  "babel-loader": "^8.3.0"
}

If this does not work, you should set api.cache(false) in your babel config, which resets Babel cache.

If you're using android, add a clean task to your run command: react-native run-android --tasks clean,installDebug

metro.config.jsresetCache: true

You can easily clear the cache:

rm -rf node_modules/.cache/babel-loader/*

or reset all caches

npm start -- --reset-cache

or

yarn start --reset-cache

or

yarn start --clear

or

jest --no-cache

or

expo r -c

and

expo start --clear

or

react-native clean

or

rm -rf .expo/web/cache

or

react-native-clean-project

Maybe a solution for updating package.json scripts:

"cc": "rimraf node_modules/.cache/babel-loader/*,",
"android": "npm run cc && react-native run-android",
"ios": "npm run cc && react-native run-ios",

Or you can override the default cacheIdentifier to include some of your environment variables.

The tests that use require('@env') are also not passing.

For nextjs, you must set moduleName to react-native-dotenv.

 

FAQ

This Babel plugin reads your .env files at build time and replaces @env imports (and matching process.env references) with their values before the React Native bundle is generated. Runtime Node process.env is not available in the app the same way.

Expo now has built-in environment variable support. Evaluate if you still need this plugin.

No. Values are inlined into your JavaScript bundle. Anyone who unpacks your app can read them. Only put public config in .env — keep real secrets on a server.

Yes. Set moduleName to react-native-dotenv (Next.js already owns @env).

{
  "plugins": [
    ["module:react-native-dotenv", {
      "moduleName": "react-native-dotenv"
    }]
  ]
}

Use dotenvx.

No.

Unless you encrypt it with dotenvx. Then we recommend you do.

Yes. The plugin inlines matching keys at build time the same way as @env imports.

console.log(`Hello ${process.env.HELLO}`)
fetch(`${process.env.API_URL}/users`)

We recommend creating one .env file per environment. Use .env for local/development, .env.production for production and so on. This still follows the twelve factor principles as each is attributed individually to its own environment. Avoid custom set ups that work in inheritance somehow (.env.production inherits values from .env for example). It is better to duplicate values if necessary across each .env.environment file.

In a twelve-factor app, env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as “environments”, but instead are independently managed for each deploy. This is a model that scales up smoothly as the app naturally expands into more deploys over its lifetime.

The Twelve-Factor App

Additionally, we recommend using dotenvx to encrypt and manage these.

This package also supports dotenv-flow-style files (.env, .env.local, .env.<mode>, .env.<mode>.local). See Multi-env under Advanced.

Use dotenvx to unlock syncing encrypted .env files over git.

Usually cache. Clear Metro/Babel cache and restart:

npm start -- --reset-cache
# or
yarn start --reset-cache
# or
expo start --clear

Also set api.cache(false) in your Babel config (see Usage), or clear node_modules/.cache/babel-loader/*. See Caching under Advanced for more.

Remove it, remove git history and then install the git pre-commit hook to prevent this from ever happening again.

npm i -g @dotenvx/dotenvx
dotenvx precommit --install

Babel/Node treat development and production specially. If you use APP_ENV (or envName), avoid those values — use something like staging / release instead. Prefer built-in NODE_ENV=development / NODE_ENV=production when you need those modes. See envName under Advanced.

@env is a virtual module created by this Babel plugin — it is not an npm package. Make sure module:react-native-dotenv is in your Babel config, restart Metro with a cache reset, and that your moduleName option matches the import (default @env).

Prefer Zod to validate and infer types — see Types with Zod under Advanced.

By default, we will never modify any environment variables that have already been set. In particular, if there is a variable in your .env file which collides with one that already exists in your environment, then that variable will be skipped (the existing value wins at build time).

process.env.X is only inlined when X appears in a .env file. Host/CI-only keys still work via import { X } from '@env'.

CHANGELOG

See CHANGELOG.md

 

Who's using react-native-dotenv?

These npm modules depend on it.

Projects that expand it often use the keyword "dotenv" on npm.

 

Credits

Long maintained by Kemal Ahmed (@goatandsheep).