Reactの環境変数とは?.envファイルの基本的な使い方

Reactでの環境変数の使い方と.envファイルの設定方法を詳しく解説。開発・本番環境での設定分離から実践的なセキュリティ対策まで初心者向けに紹介

Learning Next 運営
37 分で読めます

Reactでアプリを作るとき、「APIのURLを本番と開発で切り替えたい」「秘密鍵をコードに直接書きたくない」と思ったことはありませんか?

「開発と本番で設定が違うから管理が大変」 「APIキーをコードに書くのは危険?」 「環境変数って何?どうやって使うの?」

こんな悩みを抱えている方も多いはずです。

実は、環境変数を使えば設定管理がとても楽になります。 この記事では、Reactでの環境変数の使い方と.envファイルの設定方法を、基本的な概念から実践的なセキュリティ対策まで詳しく解説します。

初心者の方でも安心して実践できるよう、具体的な例をたくさん用意しました。 ぜひ最後まで読んで、効率的な設定管理をマスターしてくださいね!

環境変数って何?なぜ必要なの?

まずは、環境変数がどんなものなのか、なぜ必要なのかを理解しましょう。 環境変数は、アプリケーションの動作を制御するための設定値のことです。

環境変数の基本的な仕組み

// ❌ 設定値をコードに直接書く場合
function UserProfile() {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    // APIのURLがコードに直接記述されている
    fetch('https://api.example.com/user/123')
      .then(response => response.json())
      .then(data => setUser(data));
  }, []);
  
  return <div>{user?.name}</div>;
}

このように、設定値をコードに直接書いてしまうと問題が発生します。

// ✅ 環境変数を使用する場合
function UserProfile() {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    // 環境変数からAPIのURLを取得
    const apiUrl = process.env.REACT_APP_API_URL;
    
    fetch(`${apiUrl}/user/123`)
      .then(response => response.json())
      .then(data => setUser(data));
  }, []);
  
  return <div>{user?.name}</div>;
}

環境変数を使うことで、コードを変更せずに設定を切り替えられるようになります。 とても便利ですよね!

環境変数を使うメリット

環境変数を使用することで得られるメリットをご紹介します。

環境間の設定分離

  • 開発、ステージング、本番で異なる設定を使える
  • APIのURL、データベース接続情報などを環境ごとに管理

セキュリティの向上

  • 機密情報をコードに含めない
  • APIキー、パスワード、トークンを安全に管理

設定の一元管理

  • 設定値を.envファイルで一元管理
  • アプリケーション設定、機能フラグを整理

デプロイの柔軟性

  • コードを変更せずに設定を変更可能
  • CI/CDパイプラインでの環境別デプロイが簡単

これらのメリットを活用することで、より安全で保守しやすいアプリケーションが作れます。

Reactでの環境変数の特別なルール

Reactの環境変数には、他のフレームワークとは異なる特別なルールがあります。

命名規則の制約

  • REACT_APP_ で始まる必要がある
  • セキュリティのため、特定のプレフィックスのみ公開される
// ✅ 正しい命名
REACT_APP_API_URL=https://api.example.com

// ❌ 間違った命名(これは読み込まれない)
API_URL=https://api.example.com

公開性の注意点

  • 環境変数はクライアントサイドで公開される
  • ブラウザから誰でも見ることができる

含めてはいけない情報を確認しておきましょう。

  • データベースのパスワード
  • サーバーの秘密鍵
  • 管理者用のAPIキー

含めても良い情報は以下の通りです。

  • 公開APIのエンドポイント
  • アプリケーション名
  • 機能フラグ

ビルド時の決定

  • ビルド時に値が確定される
  • 実行時に動的に変更はできない
  • 環境ごとに異なるビルドを作成する必要がある

これらのルールを理解しておくことで、安全に環境変数を活用できます。

.envファイルの作り方と設定方法

環境変数の基本を理解したら、実際に.envファイルを作って設定してみましょう。 .envファイルは、環境変数を管理するためのファイルです。

.envファイルの基本的な作成方法

プロジェクトのルートディレクトリ(package.jsonと同じ場所)に.envファイルを作成します。

# プロジェクトルートに.envファイルを作成
# ファイルパス: your-react-app/.env

# API設定
REACT_APP_API_URL=http://localhost:3001/api
REACT_APP_API_VERSION=v1

# アプリケーション設定
REACT_APP_APP_NAME=My React App
REACT_APP_VERSION=1.0.0

# 機能フラグ
REACT_APP_ENABLE_ANALYTICS=true
REACT_APP_ENABLE_DARK_MODE=false

# 外部サービス設定
REACT_APP_GOOGLE_MAPS_API_KEY=your_google_maps_api_key
REACT_APP_STRIPE_PUBLIC_KEY=pk_test_your_stripe_public_key

このように、設定したい項目をキー=値の形式で記述します。 コメントは#で始めることができますよ。

環境別の.envファイルを作る

開発・本番・テストなど、環境ごとに異なる設定ファイルを作ることができます。

# 開発環境用: .env.development
REACT_APP_API_URL=http://localhost:3001/api
REACT_APP_DEBUG_MODE=true
REACT_APP_LOG_LEVEL=debug
# 本番環境用: .env.production
REACT_APP_API_URL=https://api.yourapp.com
REACT_APP_DEBUG_MODE=false
REACT_APP_LOG_LEVEL=error
# テスト環境用: .env.test
REACT_APP_API_URL=http://localhost:3001/api
REACT_APP_DEBUG_MODE=true
REACT_APP_LOG_LEVEL=warn

環境に応じて自動的に適切なファイルが読み込まれるので、とても便利です。

ファイルの読み込み優先順位

Create React Appでは、複数の.envファイルがある場合の優先順位が決まっています。

優先順位(高い順)

  1. .env.development.local(開発時)
  2. .env.local
  3. .env.development
  4. .env

重要な注意点

  • .localファイルはgitにコミットしない
  • NODE_ENVによって読み込まれるファイルが変わる
  • 後から読み込まれたファイルが優先される

この仕組みを理解しておくと、設定の管理がしやすくなります。

実際にコードで環境変数を使ってみよう

環境変数の設定ができたら、実際にコードで使ってみましょう。 よく使われる実践的な例をご紹介します。

API設定の管理

まずは、設定ファイルを作って環境変数を整理しましょう。

// config.js - 設定ファイル
const config = {
  api: {
    baseUrl: process.env.REACT_APP_API_URL || 'http://localhost:3001/api',
    version: process.env.REACT_APP_API_VERSION || 'v1',
    timeout: parseInt(process.env.REACT_APP_API_TIMEOUT) || 5000
  },
  
  app: {
    name: process.env.REACT_APP_APP_NAME || 'React App',
    version: process.env.REACT_APP_VERSION || '1.0.0',
    environment: process.env.NODE_ENV || 'development'
  },
  
  features: {
    analytics: process.env.REACT_APP_ENABLE_ANALYTICS === 'true',
    darkMode: process.env.REACT_APP_ENABLE_DARK_MODE === 'true',
    debugMode: process.env.REACT_APP_DEBUG_MODE === 'true'
  },
  
  external: {
    googleMapsApiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
    stripePublicKey: process.env.REACT_APP_STRIPE_PUBLIC_KEY
  }
};

export default config;

このconfig.jsファイルで環境変数を一元管理します。 ||演算子でデフォルト値も設定しているので安心ですね。

次に、APIクライアントを作ってみましょう。

// APIクライアントの実装
import axios from 'axios';
import config from './config';

const apiClient = axios.create({
  baseURL: `${config.api.baseUrl}/${config.api.version}`,
  timeout: config.api.timeout,
  headers: {
    'Content-Type': 'application/json'
  }
});

設定ファイルからの値を使ってAPIクライアントを作成します。 環境が変わっても、自動的に適切なURLやタイムアウト設定が使われます。

リクエストとレスポンスのインターセプターも追加してみましょう。

// リクエストインターセプター
apiClient.interceptors.request.use(
  (requestConfig) => {
    if (config.features.debugMode) {
      console.log('API Request:', requestConfig);
    }
    return requestConfig;
  },
  (error) => {
    if (config.features.debugMode) {
      console.error('API Request Error:', error);
    }
    return Promise.reject(error);
  }
);

// レスポンスインターセプター
apiClient.interceptors.response.use(
  (response) => {
    if (config.features.debugMode) {
      console.log('API Response:', response);
    }
    return response;
  },
  (error) => {
    if (config.features.debugMode) {
      console.error('API Response Error:', error);
    }
    return Promise.reject(error);
  }
);

export { apiClient };

デバッグモードが有効な場合のみログを出力するようになっています。 本番環境では不要なログが出力されないので、パフォーマンスも向上しますよ。

機能フラグの活用

機能フラグを使って、環境や設定に応じて機能を切り替えてみましょう。

// FeatureFlag.jsx - 機能フラグコンポーネント
import config from './config';

function FeatureFlag({ feature, children, fallback = null }) {
  const isEnabled = config.features[feature];
  
  if (config.features.debugMode) {
    console.log(`Feature "${feature}" is ${isEnabled ? 'enabled' : 'disabled'}`);
  }
  
  return isEnabled ? children : fallback;
}

この機能フラグコンポーネントを使って、条件付きで機能を表示できます。

// 使用例
function App() {
  return (
    <div className="app">
      <header>
        <h1>{config.app.name}</h1>
        
        {/* ダークモード機能を条件付きで表示 */}
        <FeatureFlag feature="darkMode">
          <DarkModeToggle />
        </FeatureFlag>
      </header>
      
      <main>
        <UserDashboard />
        
        {/* アナリティクス機能を条件付きで表示 */}
        <FeatureFlag feature="analytics">
          <AnalyticsPanel />
        </FeatureFlag>
      </main>
      
      {/* デバッグ情報を開発時のみ表示 */}
      <FeatureFlag feature="debugMode">
        <DebugPanel />
      </FeatureFlag>
    </div>
  );
}

機能フラグを使うことで、環境変数の設定だけで機能の有効・無効を切り替えられます。 とても柔軟で便利ですね!

デバッグパネルも作ってみましょう。

// DebugPanel.jsx - デバッグ情報表示
function DebugPanel() {
  const debugInfo = {
    environment: config.app.environment,
    apiUrl: config.api.baseUrl,
    version: config.app.version,
    enabledFeatures: Object.entries(config.features)
      .filter(([key, value]) => value)
      .map(([key]) => key)
  };
  
  return (
    <div style={{
      position: 'fixed',
      bottom: 0,
      right: 0,
      background: 'rgba(0,0,0,0.8)',
      color: 'white',
      padding: '10px',
      fontSize: '12px',
      borderRadius: '4px 0 0 0'
    }}>
      <h4>Debug Info</h4>
      <pre>{JSON.stringify(debugInfo, null, 2)}</pre>
    </div>
  );
}

開発時にアプリの現在の設定状況が一目で分かるので、とても便利です。

外部サービスとの統合

Google MapsやStripeなどの外部サービスを環境変数で管理してみましょう。

// GoogleMaps.jsx - Google Maps統合
import { useEffect, useRef } from 'react';
import config from './config';

function GoogleMaps({ center, zoom = 10 }) {
  const mapRef = useRef(null);
  const mapInstanceRef = useRef(null);
  
  useEffect(() => {
    // Google Maps API キーの確認
    if (!config.external.googleMapsApiKey) {
      console.error('Google Maps API key is not configured');
      return;
    }
    
    // Google Maps スクリプトの動的読み込み
    const loadGoogleMaps = async () => {
      if (window.google) {
        initializeMap();
        return;
      }
      
      const script = document.createElement('script');
      script.src = `https://maps.googleapis.com/maps/api/js?key=${config.external.googleMapsApiKey}`;
      script.onload = initializeMap;
      document.head.appendChild(script);
    };
    
    const initializeMap = () => {
      if (mapRef.current && window.google) {
        mapInstanceRef.current = new window.google.maps.Map(mapRef.current, {
          center,
          zoom
        });
      }
    };
    
    loadGoogleMaps();
  }, [center, zoom]);
  
  if (!config.external.googleMapsApiKey) {
    return (
      <div style={{ padding: '20px', textAlign: 'center', backgroundColor: '#f0f0f0' }}>
        Google Maps API key is not configured
      </div>
    );
  }
  
  return <div ref={mapRef} style={{ width: '100%', height: '400px' }} />;
}

APIキーが設定されていない場合の処理も含めることで、エラーを防げます。

Stripe決済の統合も見てみましょう。

// PaymentForm.jsx - Stripe決済統合
import { useEffect, useState } from 'react';
import config from './config';

function PaymentForm({ amount, onSuccess, onError }) {
  const [stripe, setStripe] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  
  useEffect(() => {
    // Stripe公開キーの確認
    if (!config.external.stripePublicKey) {
      console.error('Stripe public key is not configured');
      setIsLoading(false);
      return;
    }
    
    // Stripe.jsの動的読み込み
    const loadStripe = async () => {
      if (window.Stripe) {
        setStripe(window.Stripe(config.external.stripePublicKey));
        setIsLoading(false);
        return;
      }
      
      const script = document.createElement('script');
      script.src = 'https://js.stripe.com/v3/';
      script.onload = () => {
        setStripe(window.Stripe(config.external.stripePublicKey));
        setIsLoading(false);
      };
      document.head.appendChild(script);
    };
    
    loadStripe();
  }, []);
  
  const handlePayment = async () => {
    if (!stripe) return;
    
    try {
      // 決済処理の実装
      const { error } = await stripe.redirectToCheckout({
        lineItems: [{ price: 'price_12345', quantity: 1 }],
        mode: 'payment',
        successUrl: `${window.location.origin}/success`,
        cancelUrl: `${window.location.origin}/cancel`,
      });
      
      if (error) {
        onError(error);
      }
    } catch (error) {
      onError(error);
    }
  };
  
  if (!config.external.stripePublicKey) {
    return (
      <div style={{ padding: '20px', textAlign: 'center', backgroundColor: '#f0f0f0' }}>
        Stripe is not configured
      </div>
    );
  }
  
  if (isLoading) {
    return <div>決済システムを読み込み中...</div>;
  }
  
  return (
    <div>
      <h3>お支払い金額: ¥{amount.toLocaleString()}</h3>
      <button onClick={handlePayment}>
        決済を開始
      </button>
    </div>
  );
}

このように、外部サービスのAPIキーも環境変数で管理することで、安全で柔軟な実装ができます。

セキュリティを意識した安全な使い方

環境変数を使う際は、セキュリティを意識することがとても大切です。 安全に使用するためのベストプラクティスをご紹介します。

機密情報の適切な管理

クライアントサイドとサーバーサイドで、適切に使い分けましょう。

クライアントサイド環境変数(React)

  • ブラウザで実行されるコードで使用
  • REACT_APP_プレフィックスが必要
  • ビルド後にJavaScriptファイルに含まれる
  • 誰でも見ることができる

含めて良い情報を確認しておきましょう。

  • APIエンドポイントURL
  • Google Maps API key(制限付き)
  • Stripe公開キー
  • アプリケーション設定
  • 機能フラグ

サーバーサイド環境変数(Node.js等)

  • サーバーでのみ使用
  • プレフィックスは任意
  • クライアントには絶対に送信しない

含める情報は以下の通りです。

  • データベース接続文字列
  • JWT秘密鍵
  • サードパーティサービスの秘密鍵
  • サーバー設定
// ❌ 危険な例:機密情報をクライアントサイド環境変数に含める
// .env (危険)
// REACT_APP_DATABASE_PASSWORD=secret123
// REACT_APP_JWT_SECRET=super-secret-key
// REACT_APP_ADMIN_API_KEY=admin-key-123

// ✅ 安全な例:適切な情報のみをクライアントサイドに含める
// .env (安全)
// REACT_APP_API_URL=https://api.example.com
// REACT_APP_GOOGLE_MAPS_API_KEY=AIza...(制限付きキー)
// REACT_APP_STRIPE_PUBLIC_KEY=pk_live_...

この使い分けを間違えると、重大なセキュリティリスクにつながります。

.gitignoreの適切な設定

機密情報を含むファイルをgitにコミットしないよう設定しましょう。

# .gitignore - 機密情報を含むファイルを除外
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules

# production
/build

# environment variables
.env.local
.env.development.local
.env.test.local
.env.production.local

# 本番環境の設定ファイル(機密情報を含む可能性)
.env.production

# IDEファイル
.vscode/
.idea/

# OS generated files
.DS_Store
Thumbs.db

# ログファイル
npm-debug.log*
yarn-debug.log*
yarn-error.log*

特に.localファイルと.env.productionは必ずgitignoreに含めましょう。

環境変数の検証

環境変数が正しく設定されているかをチェックする仕組みを作りましょう。

// envValidator.js - 環境変数の検証
class EnvValidator {
  static validateRequired(envVars) {
    const missing = [];
    
    envVars.forEach(varName => {
      if (!process.env[varName]) {
        missing.push(varName);
      }
    });
    
    if (missing.length > 0) {
      throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
    }
  }
  
  static validateUrl(url, varName) {
    try {
      new URL(url);
    } catch (error) {
      throw new Error(`Invalid URL for ${varName}: ${url}`);
    }
  }
  
  static validateBoolean(value, varName) {
    if (value !== 'true' && value !== 'false' && value !== undefined) {
      throw new Error(`${varName} must be 'true' or 'false', got: ${value}`);
    }
  }
  
  static validateNumber(value, varName, min = null, max = null) {
    const num = parseInt(value);
    
    if (isNaN(num)) {
      throw new Error(`${varName} must be a number, got: ${value}`);
    }
    
    if (min !== null && num < min) {
      throw new Error(`${varName} must be >= ${min}, got: ${num}`);
    }
    
    if (max !== null && num > max) {
      throw new Error(`${varName} must be <= ${max}, got: ${num}`);
    }
  }
}

この検証クラスを使って、環境変数の妥当性をチェックできます。

// 環境変数の検証実行
try {
  // 必須環境変数のチェック
  EnvValidator.validateRequired([
    'REACT_APP_API_URL',
    'REACT_APP_APP_NAME'
  ]);
  
  // URL形式のチェック
  if (process.env.REACT_APP_API_URL) {
    EnvValidator.validateUrl(process.env.REACT_APP_API_URL, 'REACT_APP_API_URL');
  }
  
  // ブール値のチェック
  EnvValidator.validateBoolean(process.env.REACT_APP_ENABLE_ANALYTICS, 'REACT_APP_ENABLE_ANALYTICS');
  
  // 数値のチェック
  if (process.env.REACT_APP_API_TIMEOUT) {
    EnvValidator.validateNumber(process.env.REACT_APP_API_TIMEOUT, 'REACT_APP_API_TIMEOUT', 1000, 60000);
  }
  
  console.log('✅ All environment variables are valid');
  
} catch (error) {
  console.error('❌ Environment variable validation failed:', error.message);
  process.exit(1);
}

export default EnvValidator;

アプリケーション起動時にこの検証を実行することで、設定ミスを早期に発見できます。

よくある問題と解決方法

環境変数を使っていると、いくつかの問題に遭遇することがあります。 よくある問題と解決方法をご紹介しましょう。

環境変数が読み込まれない場合

環境変数がundefinedになってしまう場合の原因と解決策です。

原因1: REACT_APP_プレフィックスがない

// ❌ 間違い
API_URL=http://localhost:3001

// ✅ 正解
REACT_APP_API_URL=http://localhost:3001

環境変数名は必ずREACT_APP_で始める必要があります。

原因2: .envファイルの場所が間違っている

  • package.jsonと同じディレクトリに配置する
  • ls -laでファイルの存在を確認してみましょう

原因3: 開発サーバーの再起動が必要

  • npm startまたはyarn startを再実行
  • 環境変数はサーバー起動時に読み込まれるため

これらをチェックしても動かない場合は、デバッグ用コンポーネントを使ってみましょう。

// デバッグ用コンポーネント
function EnvironmentDebugger() {
  const envVars = {};
  
  // REACT_APP_ で始まる環境変数のみ表示
  Object.keys(process.env).forEach(key => {
    if (key.startsWith('REACT_APP_')) {
      envVars[key] = process.env[key];
    }
  });
  
  return (
    <div style={{ padding: '20px', backgroundColor: '#f5f5f5', margin: '20px' }}>
      <h3>Environment Variables Debug</h3>
      <p><strong>NODE_ENV:</strong> {process.env.NODE_ENV}</p>
      <h4>Available REACT_APP_ variables:</h4>
      <pre style={{ backgroundColor: 'white', padding: '10px', overflow: 'auto' }}>
        {JSON.stringify(envVars, null, 2)}
      </pre>
      
      {Object.keys(envVars).length === 0 && (
        <p style={{ color: 'red' }}>
          ⚠️ No REACT_APP_ environment variables found!
        </p>
      )}
    </div>
  );
}

このコンポーネントを使うことで、現在読み込まれている環境変数を確認できます。

パフォーマンスの最適化

環境変数を効率的に使用するためのテクニックをご紹介します。

// 環境変数の効率的な使用
class ConfigManager {
  constructor() {
    // 起動時に一度だけ環境変数を読み込み
    this.config = this.loadConfig();
  }
  
  loadConfig() {
    return {
      api: {
        baseUrl: process.env.REACT_APP_API_URL || 'http://localhost:3001/api',
        timeout: parseInt(process.env.REACT_APP_API_TIMEOUT) || 5000
      },
      features: {
        analytics: process.env.REACT_APP_ENABLE_ANALYTICS === 'true',
        darkMode: process.env.REACT_APP_ENABLE_DARK_MODE === 'true'
      }
    };
  }
  
  // 設定値の取得(キャッシュされた値を返す)
  get(path) {
    return path.split('.').reduce((obj, key) => obj?.[key], this.config);
  }
  
  // 設定値の存在確認
  has(path) {
    return this.get(path) !== undefined;
  }
  
  // 開発環境かどうかの判定
  isDevelopment() {
    return process.env.NODE_ENV === 'development';
  }
  
  // 本番環境かどうかの判定
  isProduction() {
    return process.env.NODE_ENV === 'production';
  }
}

const configManager = new ConfigManager();
export default configManager;

このConfigManagerを使うことで、毎回process.envにアクセスせずに済みます。

// 使用例
function ApiService() {
  const baseUrl = configManager.get('api.baseUrl');
  const timeout = configManager.get('api.timeout');
  
  // 毎回 process.env にアクセスしない効率的な実装
  const client = axios.create({
    baseURL: baseUrl,
    timeout: timeout
  });
  
  return client;
}

効率的で保守しやすいコードになりますね。

まとめ:環境変数で効率的な開発を始めよう

Reactでの環境変数の使い方と.envファイルの設定について詳しく解説しました。 環境変数を適切に活用することで、たくさんのメリットが得られます。

主なメリット

  • 環境間での設定分離
  • セキュリティの向上
  • 設定の一元管理
  • デプロイの柔軟性

重要なポイント

  • REACT_APP_プレフィックスの使用
  • 機密情報をクライアントサイドに含めない
  • 適切な.gitignore設定
  • 環境変数の検証

実践のコツ

  • 設定ファイルで一元管理
  • 機能フラグの活用
  • デバッグ用コンポーネントの作成
  • パフォーマンスの最適化

基本的な.envファイルから始めて、徐々に設定を充実させていくのがおすすめです。

最初は簡単なAPI URLの設定から始めてみてください。 慣れてきたら、機能フラグや外部サービスの統合にも挑戦してみましょう。

開発の初期段階から環境変数を意識した設計を行うことで、後々の保守が格段に楽になります。 ぜひ今回の内容を参考に、効率的で安全なReactアプリケーション開発を進めてくださいね!

関連記事