Hassan Agmir Hassan Agmir

React with Environment Variables

Hassan Agmir
React with Environment Variables

Why Environment Variables Matter in React

Environment variables let you configure your application differently for development, testing, staging, and production, without changing source code. By centralizing secrets (API keys, endpoints, feature flags) in dedicated files or systems, you:

  • Reduce risk of exposing sensitive data in version control.
  • Simplify configuration when deploying to multiple environments.
  • Enable feature toggles, letting you turn on/off features without a code redeploy.

How React Projects Load Environment Variables

Create React App (CRA)

CRA automatically loads variables from files named:

  • .env
  • .env.local
  • .env.development, .env.production, etc.
  • .env.development.local, .env.production.local, etc.

Only variables prefixed with REACT_APP_ will be embedded into the client bundle. Others are ignored. For example:

# .env.development
REACT_APP_API_URL=http://localhost:4000
REACT_APP_FEATURE_X=true

In your code, access via:

const apiUrl = process.env.REACT_APP_API_URL;
if (process.env.REACT_APP_FEATURE_X === "true") {
  // enable feature X
}

Vite / Next.js / Other Toolchains

  • Vite: uses VITE_ prefix by default; files named .env, .env.development, etc.
  • Next.js: uses NEXT_PUBLIC_ for client variables and .env.local for server only.
  • Gatsby: uses .env.* and GATSBY_ prefix for client.

Always check your chosen tool’s docs for exact naming conventions.

Structuring Your .env Files

  1. .env.local
    • Untracked by git
    • Secrets for your local machine (e.g. test API keys)
  2. .env.development / .env.development.local
    • Loaded only when running in development
  3. .env.production / .env.production.local
    • Loaded only when building for production
Tip: Commit non-secret defaults in .env.example so that other developers know which keys to supply.
# .env.example
REACT_APP_API_URL=
REACT_APP_ANALYTICS_KEY=

Best Practices

1. Never Commit Secrets

  • Add .env.local and .env.*.local to .gitignore.
  • Commit only .env.example with placeholder values.

2. Use Descriptive Names

  • Avoid REACT_APP_KEY1; instead use REACT_APP_STRIPE_PUBLIC_KEY.
  • Keep naming consistent across environments.

3. Validate at Startup

  • Early failure helps catch missing variables.
  • Create a helper to throw when a required var is absent:
function getEnv(name) {
  const value = process.env[name];
  if (!value) {
    throw new Error(`Environment variable ${name} is required`);
  }
  return value;
}

const apiUrl = getEnv("REACT_APP_API_URL");

4. Differentiate Build‐time vs Runtime Config

React bundles env vars at build time. If you need runtime changes (e.g. switching API endpoints without redeploy), consider:

  • Fetching a JSON config file on startup.
  • Embedding variables in HTML around your root <div>.

5. Avoid Exposing Secrets

Anything exposed via process.env in the client is public. For truly private keys (e.g. database credentials), use a backend or serverless function.

6. Use Feature Flags

Control new features without a rebuild:

REACT_APP_FEATURE_NEW_DASHBOARD=false

Toggle it on in production if everything’s ready.

Advanced: Runtime Injection

When you can’t rebuild to change config, use a two‐step approach:

  1. At build: bundle a placeholder:
  2. export const CONFIG = {
      apiUrl: "%REACT_APP_API_URL%",
    };
  3. At deploy: run a script to replace placeholders in build/static/js/*.js with actual values from server env.

Troubleshooting

  • Variables not found?
    • Confirm the file is named correctly and located at the project root.
    • Restart your dev server after changes.
  • Value always the same?
    • CRA reads env only once at startup; rebuild/restart after edits.
  • Empty string vs undefined?
    • An empty value (REACT_APP_FOO=) yields an empty string, not undefined. Use validation helpers accordingly.

Quick Checklist Before You Ship

  •  .env.local and .env.*.local are in .gitignore
  •  .env.example is up to date with all required keys
  •  No secret values appear in your git history
  •  Names are clear, consistent, and prefixed properly
  •  Validation code in place for required variables
  •  Runtime‐config plan ready if you need post‐build changes

By following these patterns, you’ll keep your React applications secure, configurable, and easy to maintain across all stages of development and deployment.

Subscribe to my Newsletters

Stay updated with the latest programming tips, tricks, and IT insights! Join my community to receive exclusive content on coding best practices.

© Copyright 2025 by Hassan Agmir . Built with ❤ by Me