Turborepoでの環境変数管理完全ガイド

はじめに

モノレポ管理ツールとして人気のTurborepoを使用していると、複数のアプリケーションやパッケージ間での環境変数の扱いに悩むことがあります。この記事では、Turborepoにおける環境変数の管理方法、特にNext.jsアプリケーションでの設定方法を詳しく解説します。

Turborepoにおける環境変数の基本

Turborepoでは、環境変数の管理に関して以下の重要な概念があります:

  1. env - ビルドキャッシュに影響を与える変数
  2. passThroughEnv - キャッシュに影響しない変数
  3. globalDependencies - 全タスクに影響を与えるファイルや環境変数ファイル
  4. globalEnv - 全タスクで使用される環境変数(Turborepo 2.0 以降)

これらを理解することで、効率的なビルドプロセスを実現できます。

モノレポでの環境変数の配置

Turborepoを使用するプロジェクトでは、環境変数ファイルを以下のように配置できます:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
my-turborepo/
├── .env              # ルートレベルの共通環境変数
├── .env.local        # ローカル開発用(Gitで管理しない)
├── apps/
│   ├── web/
│   │   ├── .env      # web アプリ特有の環境変数
│   │   └── .env.local
│   └── admin/
│       ├── .env      # admin アプリ特有の環境変数
│       └── .env.local
└── packages/
    └── ui/

重要なのは、Turborepoは自動的にルートの.envファイルを各ワークスペースに共有しないという点です。

turbo.json での設定 (Turborepo 2.0)

Turborepo 2.0からは、設定ファイルの構造が変更され、pipelineからtasksに変わりました。環境変数を適切に管理するには、turbo.jsonファイルで明示的に設定する必要があります:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": [".env"],
  "globalEnv": ["NODE_ENV"],
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"],
      "env": [
        "API_KEY",
        "NEXT_PUBLIC_API_URL"
      ],
      "passThroughEnv": [
        "CI",
        "VERCEL_ENV"
      ]
    },
    "dev": {
      "cache": false,
      "persistent": true,
      "env": [
        "API_KEY", 
        "NEXT_PUBLIC_API_URL"
      ]
    }
  }
}

envとpassThroughEnvの違い

この設定の中で特に重要なのが、envpassThroughEnvの違いです:

  • env:ここに指定された変数の値が変更されると、キャッシュが無効化され、再ビルドが発生します
  • passThroughEnv:ここに指定された変数はビルドプロセスに渡されますが、値が変わってもキャッシュに影響しません

例えば、開発環境と本番環境でVERCEL_ENVの値が異なっていても、API_KEYが同じであればビルドキャッシュを再利用できます。これにより、CI/CDパイプラインでのビルド時間を大幅に短縮できます。

globalDependenciesとglobalEnvの関係

globalDependenciesglobalEnvは異なる目的を持っています:

  • globalDependencies:ファイルの変更を検知してキャッシュを無効化しますが、環境変数として自動的に読み込むわけではありません
  • globalEnv:全タスクで使用される環境変数を明示的に指定します

例えば、.envファイルをglobalDependenciesに指定しただけでは、その中身が環境変数として使用できるわけではありません。.env内の変数を使うには、各タスクのenv/passThroughEnvglobalEnvで明示的に指定する必要があります:

1
2
3
4
5
6
7
8
9
{
  "globalDependencies": [".env"],
  "globalEnv": ["NODE_ENV", "API_KEY"], // .envに含まれる変数を明示的に指定
  "tasks": {
    "build": {
      "env": ["DATABASE_URL"] // .envに含まれる他の変数
    }
  }
}

Turborepo 1.x から 2.0 への変更点

Turborepo 2.0では、以下の重要な変更がありました:

  • pipelinetasks に名前変更
  • globalEnv が導入され、全タスクで使用される環境変数を指定可能に
  • globalDependencies は引き続き外部ファイル依存を指定するために利用
  • レガシーキャッシングモードの廃止と新しいデフォルトキャッシングの導入

globalEnvの適切な使い方

globalEnvは便利な機能ですが、無分別に使用するとプロジェクトのビルド効率に悪影響を及ぼす可能性があります:

  1. 使用を控えるべき場合

    • globalEnvに指定した変数が変更されると、すべてのタスクのキャッシュが無効化されます
    • 特に大規模なモノレポでは、不必要なビルド時間の増加につながります
  2. 適切な使用例

    • システム全体に影響する重要な変数のみを指定する(例:NODE_ENVCI
    • 本当にすべてのアプリ/パッケージで共通して使われる変数のみを指定する
  3. ベストプラクティス

    • アプリケーション固有の変数は各ワークスペースのturbo.jsonで管理する
    • 変更の影響範囲を必要最小限に抑え、キャッシュを最大限に活用する

実践的な環境変数管理テクニック

1. dotenv-cliの活用

複数のワークスペース間で環境変数を確実に共有するには、dotenv-cliを使うことが効果的です:

1
npm install -D dotenv-cli

ルートのpackage.jsonのスクリプトを以下のように変更します:

1
2
3
4
5
6
{
  "scripts": {
    "dev": "dotenv -- turbo run dev",
    "build": "dotenv -- turbo run build"
  }
}

これにより、ルートの.envファイルの変数が各ワークスペースのビルドプロセスに渡されます。

2. 環境変数共有パッケージの作成

大規模なプロジェクトでは、内部パッケージとして環境変数を集中管理することも検討できます:

1
2
3
4
packages/
  env/
    index.ts
    package.json

packages/env/index.tsの例:

1
2
3
4
5
export const API_URL = process.env.API_URL ?? 'http://default-api.local';
export const FEATURE_FLAGS = {
  newUI: process.env.NEXT_PUBLIC_FEATURE_NEW_UI === 'true',
  betaFeatures: process.env.NEXT_PUBLIC_BETA_FEATURES === 'true'
};

このパッケージを各アプリから使用することで、型安全な環境変数アクセスが可能になります。

3. Next.jsとの連携

Next.jsの環境変数機能とTurborepoを組み合わせる場合、以下の点に注意が必要です:

  • クライアントサイドで使用する変数はNEXT_PUBLIC_接頭辞が必要
  • ビルド時に使用する変数はturbo.jsonenvまたはpassThroughEnvに明示的に追加
  • 開発時と本番時で異なる挙動が必要な変数は.env.development.env.productionで管理

ワークスペースレベルでの環境変数管理

Turborepoの強力な機能の一つに、各ワークスペース(アプリやパッケージ)ごとに個別のturbo.jsonを定義できる点があります。これにより、特定のアプリだけに必要な環境変数設定を効率的に管理できます。

ワークスペース固有のturbo.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
my-turborepo/
├── turbo.json         # ルートレベルの設定
├── apps/
│   ├── web/
│   │   ├── turbo.json # web アプリ特有の設定
│   │   └── ...
│   └── admin/
│       ├── turbo.json # admin アプリ特有の設定
│       └── ...
└── packages/
    └── ...

ワークスペースでのenv/passThroughEnvの設定 (Turborepo 2.0)

各ワークスペースのturbo.jsonでは、envpassThroughEnvを個別に設定できます:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// apps/web/turbo.json
{
  "extends": ["//"],
  "tasks": {
    "build": {
      "env": ["WEB_API_KEY", "NEXT_PUBLIC_WEB_FEATURE_FLAG"],
      "passThroughEnv": ["WEB_SPECIFIC_VAR"]
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// apps/admin/turbo.json
{
  "extends": ["//"],
  "tasks": {
    "build": {
      "env": ["ADMIN_API_KEY", "NEXT_PUBLIC_ADMIN_FEATURE"],
      "passThroughEnv": ["ADMIN_SPECIFIC_VAR"]
    }
  }
}

アプリごとに設定すべき理由

アプリごとにturbo.jsonで環境変数を設定するメリットは以下の通りです:

  1. キャッシュの効率化

    • アプリAの環境変数が変更されても、アプリBのキャッシュは無効化されません
    • これにより、ビルド時間が大幅に削減されます
  2. 設定の明確化

    • どの環境変数がどのアプリに必要なのかが明確になります
    • コードベースが大きくなっても管理しやすい構造を維持できます
  3. 責任の分離

    • 各アプリのチームが自分たちの環境変数を管理できます
    • 他のアプリへの影響を心配せずに変更できます

重要なポイント

  1. extends: ["//"] - このコマンドでルートのturbo.jsonの設定を継承します
  2. 設定のマージ - ワークスペースの設定はルートの設定とマージされます。つまり、両方のenv/passThroughEnv配列に定義された変数が有効になります
  3. スコープの限定 - webアプリの環境変数はadminアプリのキャッシュに影響しません

実際のユースケース

開発環境と本番環境での切り替え

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// turbo.json (Turborepo 2.0)
{
  "tasks": {
    "build": {
      "env": [
        "NEXT_PUBLIC_API_URL",
        "DATABASE_URL"
      ],
      "passThroughEnv": [
        "NODE_ENV",
        "VERCEL_ENV"
      ]
    }
  }
}
1
2
3
4
5
# .env.development
NEXT_PUBLIC_API_URL=http://localhost:3001/api

# .env.production
NEXT_PUBLIC_API_URL=https://api.example.com

このようにすることで、環境に応じた設定を維持しながらも、不要な再ビルドを避けることができます。

機密情報の扱い

APIキーなどの機密情報は、.env.localファイルに保存し、バージョン管理から除外します:

1
2
3
4
5
# .env.example
API_KEY=your-api-key-here

# .env.local(Gitにコミットしない)
API_KEY=actual-secret-key

CI/CD環境では、環境変数をVercelやGitHub Actionsで設定することでセキュリティを確保します。

まとめ

Turborepoにおける環境変数管理は、以下のポイントを押さえることで効率的に行えます:

  1. envpassThroughEnvを適切に使い分ける
  2. globalDependenciesglobalEnvの違いを理解し、適切に使用する
  3. アプリ固有の変数はワークスペースレベルのturbo.jsonで管理する
  4. 本当にグローバルな性質を持つ変数だけをglobalEnvに指定する
  5. 必要に応じてdotenv-cliや専用パッケージを活用する
  6. 機密情報は.env.localで管理し、バージョン管理から除外する
  7. Turborepo 2.0ではpipelineからtasksに変更され、globalEnvが導入されたことに注意する

これらのテクニックを活用することで、複数のNext.jsアプリを含むTurborepoプロジェクトでも、環境変数を効率的に管理できるようになります。

モノレポの規模が大きくなるほど、環境変数の管理は複雑になりがちですが、Turborepoの機能を理解して活用することで、開発体験を向上させつつ、ビルド時間も短縮できます。ぜひ、自分のプロジェクトに合った環境変数管理の戦略を見つけてください。

comments powered by Disqus