Netlify: env vars not loading in functions [2026 fix]
Netlify Functions can't access .env vars because they're not being passed at build time. Fix: add env vars to Netlify UI or use netlify.toml.
Netlify: env vars not loading in functions [2026 fix]
TL;DR
Cause: Environment variables defined in.env files aren't automatically injected into Netlify Functions at runtime.
Fix: Define variables in Netlify UI (Site Settings → Environment) or explicitly in netlify.toml.---
Real Console Error Messages
Here are exact error patterns you'll see at 2am:
``` 1. TypeError: Cannot read property 'database_url' of undefined at Object.<anonymous> (/var/task/functions/api.js:5:23)
2. Error: Missing required environment variable: STRIPE_SECRET_KEY at validateEnv (/var/task/functions/checkout.js:12:8)
3. ReferenceError: process.env.API_TOKEN is not defined at handler (/var/task/functions/webhook.js:8:15)
4. ValidationError: DATABASE_URL must be set before connecting at new Pool (/node_modules/pg/lib/index.js:45:12)
5. TypeError: Cannot destructure property 'AWS_REGION' of 'process.env' as it is undefined at exports.handler (/var/task/functions/upload.js:3:5) ```
---
Broken vs. Fixed Code
❌ BROKEN: Relying on .env file alone
```javascript // netlify/functions/api.js require('dotenv').config();
exports.handler = async (event) => { const dbUrl = process.env.DATABASE_URL; // undefined! const stripe = require('stripe')(process.env.STRIPE_KEY); // undefined! return { statusCode: 200, body: JSON.stringify({ db: dbUrl }) }; }; ```
Why it breaks: .env files are NOT bundled into Netlify Functions. They're for local development only. Functions run in Netlify's isolated Lambda environment with zero access to your repo's .env.
---
✅ FIXED: Option A - Netlify UI (Recommended for production)
1. Go to Site Settings → Environment
2. Add your variables:
- DATABASE_URL: postgres://user:pass@host/db
- STRIPE_KEY: sk_live_...
- API_TOKEN: your-token-here
3. Redeploy your site (existing deploys won't pick up new vars)
Your function code stays exactly the same—no changes needed:
```javascript // netlify/functions/api.js exports.handler = async (event) => { const dbUrl = process.env.DATABASE_URL; // now defined! const stripe = require('stripe')(process.env.STRIPE_KEY); return { statusCode: 200, body: JSON.stringify({ db: dbUrl }) }; }; ```
---
✅ FIXED: Option B - netlify.toml (For development + production)
Create/edit netlify.toml in your repo root:
```toml
❌ WRONG - this only works for build process
[build] environment = { DATABASE_URL = "postgres://localhost/test" }✅ CORRECT - this works for functions
[functions] node_bundler = "esbuild" directory = "netlify/functions"[[redirects]] from = "/api/*" to = "/.netlify/functions/:splat" status = 200
For local dev ONLY (not pushed to prod)
[context.dev.environment] DATABASE_URL = "postgres://localhost/test" STRIPE_KEY = "sk_test_..." ```⚠️ Important: Use .env.example for secrets, never commit .env. For production, STILL add vars through Netlify UI.
---
✅ FIXED: Option C - Validate early
Add validation to fail fast:
```javascript // netlify/functions/api.js const requiredEnvVars = ['DATABASE_URL', 'STRIPE_KEY', 'API_TOKEN'];
const missingVars = requiredEnvVars.filter(v => !process.env[v]);
if (missingVars.length > 0) {
console.error(Missing env vars: ${missingVars.join(', ')});
throw new Error('Environment configuration incomplete');
}
exports.handler = async (event) => { const dbUrl = process.env.DATABASE_URL; const stripe = require('stripe')(process.env.STRIPE_KEY); return { statusCode: 200, body: JSON.stringify({ status: 'ok' }) }; }; ```
---
Still broken? Check these too
1. Forgot to redeploy after adding vars? New env vars only apply to NEW deployments. Push a commit or manually trigger redeploy in Netlify UI.
2. Using wrong scope—build vs. functions: Build environment variables (set during npm run build) don't transfer to functions. Functions need their own variables in the Environment tab.
3. Function timeout before env loading: If function loads vars from external source (SSM, Vault), add timeout buffer. [Troubleshooting Netlify function timeouts](/?guide=netlify-timeout) has patterns.
---
Version-specific notes
netlify.toml specifies node_runtime = "18.x" or higher for modern syntax support.---
Related guides
---
Official docs
[Netlify Environment Variables Documentation](https://docs.netlify.com/environment-variables/overview/) [Netlify Functions Environment Setup](https://docs.netlify.com/functions/overview/?fn-language=ts)
---
Found a different variation? Drop it in the comments—this guide will be updated with community findings.