# Environment Variable Gotchas

Common mistakes and how to fix them.

## .env Files Must Be in `inputs`

Turbo does NOT read `.env` files. Your framework (Next.js, Vite, etc.) or `dotenv` loads them. But Turbo needs to know when they change.

**Wrong:**

```json
{
  "tasks": {
    "build": {
      "env": ["DATABASE_URL"]
    }
  }
}
```

**Right:**

```json
{
  "tasks": {
    "build": {
      "env": ["DATABASE_URL"],
      "inputs": ["$TURBO_DEFAULT$", ".env", ".env.local", ".env.production"]
    }
  }
}
```

## Strict Mode Filters CI Variables

In strict mode, CI provider variables (GITHUB_TOKEN, GITLAB_CI, etc.) are filtered unless explicitly listed.

**Symptom:** Task fails with "authentication required" or "permission denied" in CI.

**Solution:**

```json
{
  "globalPassThroughEnv": ["GITHUB_TOKEN", "GITLAB_CI", "CI"]
}
```

## passThroughEnv Doesn't Affect Hash

Variables in `passThroughEnv` are available at runtime but changes WON'T trigger rebuilds.

**Dangerous example:**

```json
{
  "tasks": {
    "build": {
      "passThroughEnv": ["API_URL"]
    }
  }
}
```

If `API_URL` changes from staging to production, Turbo may serve a cached build pointing to the wrong API.

**Use passThroughEnv only for:**

- Auth tokens that don't affect output (SENTRY_AUTH_TOKEN)
- CI metadata (GITHUB_RUN_ID)
- Variables consumed after build (deploy credentials)

## Runtime-Created Variables Are Invisible

Turbo captures env vars at startup. Variables created during execution aren't seen.

**Won't work:**

```bash
# In package.json scripts
"build": "export API_URL=$COMPUTED_VALUE && next build"
```

**Solution:** Set vars before invoking turbo:

```bash
API_URL=$COMPUTED_VALUE turbo run build
```

## Different .env Files for Different Environments

If you use `.env.development` and `.env.production`, both should be in inputs.

```json
{
  "tasks": {
    "build": {
      "inputs": [
        "$TURBO_DEFAULT$",
        ".env",
        ".env.local",
        ".env.development",
        ".env.development.local",
        ".env.production",
        ".env.production.local"
      ]
    }
  }
}
```

## Complete Next.js Example

```json
{
  "$schema": "https://turborepo.dev/schema.v2.json",
  "globalEnv": ["CI", "NODE_ENV", "VERCEL"],
  "globalPassThroughEnv": ["GITHUB_TOKEN", "VERCEL_URL"],
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "env": [
        "DATABASE_URL",
        "NEXT_PUBLIC_*",
        "!NEXT_PUBLIC_ANALYTICS_ID"
      ],
      "passThroughEnv": ["SENTRY_AUTH_TOKEN"],
      "inputs": [
        "$TURBO_DEFAULT$",
        ".env",
        ".env.local",
        ".env.production",
        ".env.production.local"
      ],
      "outputs": [".next/**", "!.next/cache/**"]
    }
  }
}
```

This config:

- Hashes DATABASE*URL and NEXT_PUBLIC*\* vars (except analytics)
- Passes through SENTRY_AUTH_TOKEN without hashing
- Includes all .env file variants in the hash
- Makes CI tokens available globally
