React Environment Variables
Introduction
Environment variables are a crucial part of modern web application development, especially when deploying React applications to different environments like development, staging, and production. They allow you to store configuration data outside your application code, keeping sensitive information like API keys secure while also enabling environment-specific configurations.
In this guide, we'll explore how to use environment variables in React applications, why they're important, and best practices for implementing them in your projects.
Why Use Environment Variables?
Before diving into implementation details, let's understand why environment variables are essential:
- Security: Keep sensitive information like API keys and passwords out of your codebase
- Environment-specific configuration: Use different settings for development, testing, and production
- Simplify deployment: Change configuration without modifying code
- Avoid hardcoding: Prevent hard-to-maintain values scattered throughout your code
Environment Variables in Create React App
Create React App (CRA) has built-in support for environment variables. Let's explore how to use them:
Built-in Environment Variables
CRA provides a default environment variable called NODE_ENV
. Its value depends on the command you're running:
npm start
:NODE_ENV
is set todevelopment
npm test
:NODE_ENV
is set totest
npm run build
:NODE_ENV
is set toproduction
You can access this variable in your code as process.env.NODE_ENV
:
import React from 'react';
function EnvironmentInfo() {
return (
<div>
<h2>Current Environment: {process.env.NODE_ENV}</h2>
{process.env.NODE_ENV === 'development' && (
<p>You are in development mode!</p>
)}
</div>
);
}
export default EnvironmentInfo;
Custom Environment Variables
To create custom environment variables, prefix them with REACT_APP_
in your .env
files:
REACT_APP_API_URL=https://api.example.com
REACT_APP_API_KEY=your-api-key
These can be accessed in your code as process.env.REACT_APP_API_URL
and process.env.REACT_APP_API_KEY
.
Only variables that start with REACT_APP_
will be embedded in your built application. Other variables will be ignored for security reasons.
Example: Using an API Key
Let's see how to use an environment variable to store an API key:
import React, { useState, useEffect } from 'react';
function WeatherWidget() {
const [weatherData, setWeatherData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchWeather = async () => {
try {
// Using environment variable for the API key
const apiKey = process.env.REACT_APP_WEATHER_API_KEY;
const response = await fetch(
`https://api.weatherservice.com/data?key=${apiKey}&city=NewYork`
);
if (!response.ok) {
throw new Error('Weather data fetch failed');
}
const data = await response.json();
setWeatherData(data);
setLoading(false);
} catch (err) {
setError(err.message);
setLoading(false);
}
};
fetchWeather();
}, []);
if (loading) return <div>Loading weather data...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<h2>Weather in {weatherData.city}</h2>
<p>Temperature: {weatherData.temperature}°C</p>
<p>Condition: {weatherData.condition}</p>
</div>
);
}
export default WeatherWidget;
Setting Up Different Environment Files
CRA supports different .env
files for various environments:
.env
: Default file loaded in all environments.env.development
: Used during development (npm start
).env.test
: Used during testing (npm test
).env.production
: Used during production build (npm run build
)
Additionally, you can create local variants that aren't committed to your repository:
.env.local
: Loaded for all environments except test.env.development.local
,.env.test.local
,.env.production.local
The priority order (from highest to lowest) is:
.env.{environment}.local
.env.{environment}
.env.local
.env
Example Environment Files
Here's an example of different environment files:
.env
(default for all environments):
REACT_APP_WEBSITE_NAME=My Amazing React App
.env.development
(development-specific):
REACT_APP_API_URL=http://localhost:3001/api
REACT_APP_DEBUG_MODE=true
.env.production
(production-specific):
REACT_APP_API_URL=https://api.myamazingapp.com
REACT_APP_DEBUG_MODE=false
Accessing Environment Variables
To use these variables in your React components:
import React from 'react';
function Header() {
return (
<header>
<h1>{process.env.REACT_APP_WEBSITE_NAME}</h1>
{process.env.REACT_APP_DEBUG_MODE === 'true' && (
<div className="debug-banner">Debug Mode Active</div>
)}
</header>
);
}
export default Header;
Environment Variables at Build Time vs. Runtime
An important concept to understand is that environment variables in Create React App are embedded during the build process, not at runtime.
This means:
- Values are "baked in" when you run
npm run build
- To change values after building, you need to rebuild the application
- You can't change environment variables after deployment without rebuilding
Runtime Environment Configuration
For truly dynamic configuration, you can:
- Create a configuration file that's loaded at runtime
- Use a server-side approach to inject variables
Here's a simple runtime configuration approach:
public/config.js:
window.RUNTIME_CONFIG = {
API_URL: "https://api.example.com",
FEATURE_FLAGS: {
NEW_DASHBOARD: true
}
};
Include this in your public/index.html
:
<script src="%PUBLIC_URL%/config.js"></script>
Then use it in your components:
function ApiService() {
// Use runtime config if available, fall back to build-time env var
const apiUrl = window.RUNTIME_CONFIG?.API_URL || process.env.REACT_APP_API_URL;
// Now use apiUrl for API calls
// ...
}
Security Considerations
Keep these security points in mind:
- Environment variables are embedded in the build: They are visible in the JavaScript bundle. Never include sensitive secrets in frontend code.
- API keys exposed to clients: If you include API keys in your React app, users can extract them. Use backend proxies for sensitive APIs.
- Use
.env.local
for secrets: Add local-only env files to your.gitignore
to avoid committing secrets.
Practical Example: Feature Flags
Here's a real-world example of using environment variables for feature flags:
import React from 'react';
function App() {
return (
<div className="app">
<header>
<h1>{process.env.REACT_APP_WEBSITE_NAME}</h1>
</header>
<main>
{/* Feature flag for new dashboard */}
{process.env.REACT_APP_ENABLE_NEW_DASHBOARD === 'true' ? (
<NewDashboard />
) : (
<LegacyDashboard />
)}
{/* Feature flag for experimental features */}
{process.env.REACT_APP_ENABLE_EXPERIMENTS === 'true' && (
<ExperimentalFeatures />
)}
</main>
</div>
);
}
function NewDashboard() {
return <div className="dashboard">New Dashboard Experience</div>;
}
function LegacyDashboard() {
return <div className="dashboard">Classic Dashboard</div>;
}
function ExperimentalFeatures() {
return <div className="experimental">Experimental Feature Section</div>;
}
export default App;
Using TypeScript with Environment Variables
If you're using TypeScript with React, you can enhance type safety for environment variables:
Create a react-app-env.d.ts
file (CRA might have already generated one):
/// <reference types="react-scripts" />
declare namespace NodeJS {
interface ProcessEnv {
NODE_ENV: 'development' | 'production' | 'test';
REACT_APP_API_URL: string;
REACT_APP_API_KEY: string;
REACT_APP_ENABLE_NEW_DASHBOARD: string;
// Add other env variables here
}
}
This gives you proper type checking and autocomplete for your environment variables.
Environment Variables Beyond Create React App
If you're not using CRA, you can set up environment variables with:
- Webpack: Use
DefinePlugin
ordotenv-webpack
plugin - Vite: Uses
.env
files similar to CRA, but withVITE_
prefix instead - Next.js: Has its own environment variables system with server-side and client-side variables
Summary
Environment variables are a powerful tool in React applications that help you:
- Configure your application for different environments
- Keep sensitive data out of your codebase
- Implement feature flags for gradual rollouts
- Make your application more maintainable and configurable
Remember these key points:
- In Create React App, use the
REACT_APP_
prefix for custom variables - Environment variables are embedded at build time, not runtime
- Never put truly sensitive information in frontend code
- Use different
.env
files for different environments
Additional Resources
- Create React App: Environment Variables Documentation
- Twelve-Factor App Methodology: Config
- Handling Secrets in Frontend Applications (Best Practices)
Exercises
- Create a React application that uses environment variables to switch between a local API and a production API.
- Implement a feature flag system using environment variables to enable/disable certain components.
- Set up a development, staging, and production environment configuration with appropriate
.env
files. - Create a runtime configuration system that allows changing settings without rebuilding the application.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)