# How Environment Variables Work in Create React App: Build-Time Injection Explained

> Learn how Create React App injects environment variables at build time. Understand the `.env` file process and access them via process.env in your React code.

- Repository: [Meta/create-react-app](https://github.com/facebook/create-react-app)
- Tags: deep-dive
- Published: 2026-02-26

---

**Create React App injects environment variables at build time by loading `.env` files, filtering for the `REACT_APP_` prefix, and embedding the values into your JavaScript bundle using webpack's DefinePlugin, making them accessible via `process.env` in your React code.**

**Create React App (CRA)** from the **facebook/create-react-app** repository provides a zero-configuration system for managing **environment variables in Create React App** through a secure, compile-time injection pipeline. Understanding how these variables flow from your `.env` files into the running application requires examining the build process orchestrated by the `react-scripts` package.

## The Environment Variable Pipeline in `react-scripts`

The core logic resides in **[`packages/react-scripts/config/env.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/env.js)**, which executes during the build to transform your environment files into injectable code. This module handles file discovery, variable filtering, and webpack configuration generation in a strict sequence.

### Loading and Parsing `.env*` Files

CRA automatically discovers and loads environment files based on your current `NODE_ENV`. According to the source code in [`env.js`](https://github.com/facebook/create-react-app/blob/main/env.js) (lines 25‑34), the framework looks for files in this specific order:

- `.env`
- `.env.local`
- `.env.development` or `.env.production` (depending on the current environment)
- `.env.development.local` or `.env.production.local`

Each existing file is parsed using **dotenv** and **dotenv-expand** (lines 36‑48) to resolve variable references and expand values before injection.

### Normalizing `NODE_PATH`

Before processing variables, CRA resolves any relative paths defined in **`NODE_PATH`** to ensure consistent module resolution across monorepos (lines 51‑65). This normalization step guarantees that custom import paths work correctly regardless of where the build command is executed.

## The `REACT_APP_` Prefix Filter

Not all environment variables reach your React code. The [`env.js`](https://github.com/facebook/create-react-app/blob/main/env.js) module enforces a strict naming convention using the RegExp `/^REACT_APP_/i` (line 69) to filter variables. Only names matching this pattern (case-insensitive) are retained for the client bundle.

**`NODE_ENV`** is automatically included in the final environment object regardless of prefix, providing access to `'development'`, `'production'`, or `'test'` values within your application logic.

## Build-Time Injection via `getClientEnvironment`

The **`getClientEnvironment(publicUrl)`** function (line 71) constructs the final environment object consumed by **webpack**. This function returns two critical structures:

- **`raw`** (lines 72‑83): Contains the plain string values that will be accessible in your application code
- **`stringified`** (lines 101‑107): Contains JSON-stringified versions of each value for safe injection into webpack's **DefinePlugin**

When webpack processes your code, the DefinePlugin replaces all occurrences of `process.env.REACT_APP_VARIABLE_NAME` with the actual string value at compile time. This means the final bundle contains hardcoded strings rather than runtime environment lookups.

## Using Environment Variables in Your Application

Once configured in your **`.env`** files, variables become accessible throughout your React components and utility modules.

### Accessing Variables in JavaScript

Define your variables in the project root:

```text

# .env

REACT_APP_API_URL=https://api.example.com
REACT_APP_ENABLE_ANALYTICS=true

```

Access them using the global `process.env` object:

```javascript
// src/config/api.js
const apiUrl = process.env.REACT_APP_API_URL;
const analyticsEnabled = process.env.REACT_APP_ENABLE_ANALYTICS === 'true';

export { apiUrl, analyticsEnabled };

```

### Injecting Variables into HTML

Starting with `react-scripts@0.9.0`, you can reference environment variables directly in **[`public/index.html`](https://github.com/facebook/create-react-app/blob/main/public/index.html)** using the `%VARIABLE_NAME%` syntax:

```html
<!-- public/index.html -->
<title>%REACT_APP_SITE_TITLE%</title>
<meta name="description" content="%REACT_APP_SITE_DESCRIPTION%">

```

During the build process, CRA replaces these placeholders with the corresponding environment values, allowing dynamic meta tags and titles without ejecting.

## Environment-Specific Configuration

CRA supports cascading configuration files that allow different settings for development and production environments. When you run `npm start`, CRA loads `.env.development`; when you run `npm run build`, it loads `.env.production`.

Create environment-specific overrides:

```text

# .env.production

REACT_APP_API_URL=https://api.prod.example.com
REACT_APP_DEBUG_MODE=false

```

Local overrides using the **`.local`** suffix take precedence and should be added to `.gitignore` to prevent committing sensitive machine-specific values:

```text

# .env.local

REACT_APP_LOCAL_SECRET=development-key-only

```

### Temporary Shell Variables

For one-off testing without modifying files, you can prefix the npm command on Unix systems:

```bash
REACT_APP_TEMP_TOKEN=abc123 npm start

```

## Security and Performance Considerations

**Build-time embedding** means environment variables become literal strings in your static JavaScript files. This architecture provides two critical constraints:

1. **No runtime changes**: You cannot modify environment variables after building the application without triggering a new build
2. **No secrets in client code**: Because values are visible in the bundled JavaScript served to browsers, CRA documentation explicitly warns against storing API keys, database credentials, or other secrets in `REACT_APP_` variables

The webpack DefinePlugin configuration generated by [`env.js`](https://github.com/facebook/create-react-app/blob/main/env.js) looks conceptually like this:

```javascript
// Simplified representation of the internal webpack configuration
new webpack.DefinePlugin({
  'process.env': {
    NODE_ENV: '"production"',
    PUBLIC_URL: '"/"',
    REACT_APP_API_URL: '"https://api.example.com"',
    REACT_APP_ENABLE_ANALYTICS: '"true"'
  }
});

```

## Summary

- Environment variables in Create React App are processed at build time by **[`packages/react-scripts/config/env.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/env.js)**, not at runtime
- Only variables prefixed with **`REACT_APP_`** are exposed to the client bundle, alongside the automatic **`NODE_ENV`** and **`PUBLIC_URL`**
- The system loads `.env` files in a specific precedence order, with `.local` variants overriding base files
- Values are embedded via webpack's **DefinePlugin**, transforming `process.env.VAR_NAME` references into static strings in the final bundle
- Variables can be injected into **[`public/index.html`](https://github.com/facebook/create-react-app/blob/main/public/index.html)** using the `%REACT_APP_VAR%` placeholder syntax
- Never store secrets in `REACT_APP_` variables since they become visible in the compiled static assets

## Frequently Asked Questions

### Why do my environment variables need the `REACT_APP_` prefix?

Create React App intentionally filters environment variables using the RegExp `/^REACT_APP_/i` (as implemented in [`env.js`](https://github.com/facebook/create-react-app/blob/main/env.js) line 69) to prevent accidental exposure of system-level variables to the client-side bundle. This security measure ensures that only explicitly intended variables become part of your public JavaScript code, while server-side or shell variables remain isolated from the browser.

### Can I change environment variables after building the app?

No. Because CRA embeds environment variables at build time using webpack's DefinePlugin, the values become hardcoded strings in your static JavaScript files. To change a variable's value, you must rebuild the application. This differs from server-side Node.js applications where `process.env` is evaluated at runtime.

### How do I use environment variables in [`public/index.html`](https://github.com/facebook/create-react-app/blob/main/public/index.html)?

Starting with `react-scripts@0.9.0`, you can reference any `REACT_APP_` variable in [`public/index.html`](https://github.com/facebook/create-react-app/blob/main/public/index.html) using the percent-sign syntax: `%REACT_APP_VARIABLE_NAME%`. During the build process, CRA replaces these placeholders with the actual values from your environment files, enabling dynamic titles, meta tags, and CDN URLs without ejecting from the default configuration.

### What is the order of precedence for `.env` files in Create React App?

CRA loads files in a specific sequence where later files override earlier ones: first `.env`, then `.env.local`, followed by `.env.development` or `.env.production` (depending on the current `NODE_ENV`), and finally `.env.development.local` or `.env.production.local`. This hierarchy allows you to define default values in `.env` while overriding them with environment-specific or local-only settings.