Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Configure and optimize Turborepo monorepo build pipelines with correct task structure, caching, and CI setup.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/environment/gotchas.md
1# Environment Variable Gotchas23Common mistakes and how to fix them.45## .env Files Must Be in `inputs`67Turbo does NOT read `.env` files. Your framework (Next.js, Vite, etc.) or `dotenv` loads them. But Turbo needs to know when they change.89**Wrong:**1011```json12{13"tasks": {14"build": {15"env": ["DATABASE_URL"]16}17}18}19```2021**Right:**2223```json24{25"tasks": {26"build": {27"env": ["DATABASE_URL"],28"inputs": ["$TURBO_DEFAULT$", ".env", ".env.local", ".env.production"]29}30}31}32```3334## Strict Mode Filters CI Variables3536In strict mode, CI provider variables (GITHUB_TOKEN, GITLAB_CI, etc.) are filtered unless explicitly listed.3738**Symptom:** Task fails with "authentication required" or "permission denied" in CI.3940**Solution:**4142```json43{44"globalPassThroughEnv": ["GITHUB_TOKEN", "GITLAB_CI", "CI"]45}46```4748## passThroughEnv Doesn't Affect Hash4950Variables in `passThroughEnv` are available at runtime but changes WON'T trigger rebuilds.5152**Dangerous example:**5354```json55{56"tasks": {57"build": {58"passThroughEnv": ["API_URL"]59}60}61}62```6364If `API_URL` changes from staging to production, Turbo may serve a cached build pointing to the wrong API.6566**Use passThroughEnv only for:**6768- Auth tokens that don't affect output (SENTRY_AUTH_TOKEN)69- CI metadata (GITHUB_RUN_ID)70- Variables consumed after build (deploy credentials)7172## Runtime-Created Variables Are Invisible7374Turbo captures env vars at startup. Variables created during execution aren't seen.7576**Won't work:**7778```bash79# In package.json scripts80"build": "export API_URL=$COMPUTED_VALUE && next build"81```8283**Solution:** Set vars before invoking turbo:8485```bash86API_URL=$COMPUTED_VALUE turbo run build87```8889## Different .env Files for Different Environments9091If you use `.env.development` and `.env.production`, both should be in inputs.9293```json94{95"tasks": {96"build": {97"inputs": [98"$TURBO_DEFAULT$",99".env",100".env.local",101".env.development",102".env.development.local",103".env.production",104".env.production.local"105]106}107}108}109```110111## Complete Next.js Example112113```json114{115"$schema": "https://v2-9-12.turborepo.dev/schema.json",116"globalEnv": ["CI", "NODE_ENV", "VERCEL"],117"globalPassThroughEnv": ["GITHUB_TOKEN", "VERCEL_URL"],118"tasks": {119"build": {120"dependsOn": ["^build"],121"env": ["DATABASE_URL", "NEXT_PUBLIC_*", "!NEXT_PUBLIC_ANALYTICS_ID"],122"passThroughEnv": ["SENTRY_AUTH_TOKEN"],123"inputs": [124"$TURBO_DEFAULT$",125".env",126".env.local",127".env.production",128".env.production.local"129],130"outputs": [".next/**", "!.next/cache/**"]131}132}133}134```135136This config:137138- Hashes DATABASE*URL and NEXT_PUBLIC*\* vars (except analytics)139- Passes through SENTRY_AUTH_TOKEN without hashing140- Includes all .env file variants in the hash141- Makes CI tokens available globally142143### With `futureFlags.globalConfiguration`144145The same config using the `global` key. The `.env` files move to `global.inputs`, which means they get folded into each task's hash individually rather than the global hash. This lets tasks exclude specific `.env` files if needed.146147```json148{149"$schema": "https://v2-9-12.turborepo.dev/schema.json",150"futureFlags": { "globalConfiguration": true },151"global": {152"env": ["CI", "NODE_ENV", "VERCEL"],153"passThroughEnv": ["GITHUB_TOKEN", "VERCEL_URL"],154"inputs": [".env", ".env.local", ".env.production", ".env.production.local"]155},156"tasks": {157"build": {158"dependsOn": ["^build"],159"env": ["DATABASE_URL", "NEXT_PUBLIC_*", "!NEXT_PUBLIC_ANALYTICS_ID"],160"passThroughEnv": ["SENTRY_AUTH_TOKEN"],161"outputs": [".next/**", "!.next/cache/**"]162}163}164}165```166167With this approach, a task that doesn't care about `.env.production` can exclude it:168169```json170"lint": {171"inputs": ["$TURBO_DEFAULT$", "!$TURBO_ROOT$/.env.production"]172}173```174175This wouldn't have been possible with `globalDependencies`, where `.env.production` would be baked into the global hash and affect every task unconditionally.176