Netlify: env vars not loading in functions [2026 fix]
Environment variables aren't passed to serverless functions because they're defined in UI but not exposed to function runtime context.
Netlify: Env Vars Not Loading in Functions – 2am Emergency Fix
TL;DR
Cause: Environment variables defined in Netlify UI don't automatically inject into serverless function scope unless explicitly configured innetlify.toml.
Fix: Add your vars to [functions] section in netlify.toml with proper scoping, then redeploy.---
Real Console Error Messages
You'll see one or more of these in your function logs:
``` ReferenceError: process is not defined at /var/task/index.js:12:5 ```
``` TypeError: Cannot read property 'API_KEY' of undefined at Runtime.handler (/var/task/lambda.js:45:23) ```
``` [Function] - Error: process.env.DATABASE_URL is undefined at connectDB (file:///var/task/db.js:8:1) ```
``` {"errorMessage":"SLACK_WEBHOOK_URL is not defined","errorType":"ReferenceError"} ```
``` Netlify function environment: NODE_ENV is 'production' but NEXT_PUBLIC_API_URL undefined ```
---
Broken Code vs. Exact Fix
❌ Broken Setup
netlify.toml (missing function env config): ```toml [build] command = "npm run build" functions = "netlify/functions"
Variables defined here but NOT passed to functions
[context.production] environment = { API_KEY = "sk-prod123", DATABASE_URL = "postgres://..." } ```netlify/functions/api.js: ```javascript exports.handler = async (event) => { // This will be undefined even though API_KEY exists in Netlify UI const apiKey = process.env.API_KEY; console.log(apiKey); // logs: undefined return { statusCode: 500, body: "API key missing" }; }; ```
---
✅ Exact Fix
netlify.toml (corrected): ```toml [build] command = "npm run build" functions = "netlify/functions"
Define vars at root level AND in functions section
[context.production] environment = { API_KEY = "sk-prod123", DATABASE_URL = "postgres://..." }CRITICAL: Explicitly scope env vars to functions
[functions] node_bundler = "esbuild" [[functions.environment_vars]] variables = { API_KEY = "sk-prod123", DATABASE_URL = "postgres://..." } ```Better approach using .env.production (recommended):
netlify.toml: ```toml [build] command = "npm run build" functions = "netlify/functions"
[context.production] # Load from file instead of hardcoding environment = { } ```
.env.production (git-ignored, set in Netlify UI): ``` API_KEY=sk-prod123 DATABASE_URL=postgres://user:pass@host/db SLACK_WEBHOOK_URL=https://hooks.slack.com/... ```
netlify/functions/api.js (same code now works):
```javascript
exports.handler = async (event) => {
const apiKey = process.env.API_KEY;
const dbUrl = process.env.DATABASE_URL;
console.log(Using API key: ${apiKey}); // NOW defined
return {
statusCode: 200,
body: JSON.stringify({ connected: true })
};
};
```
---
Deployment Steps
1. Update netlify.toml with function-scoped environment variables
2. Set vars in Netlify UI: Site Settings → Environment → Add variable
3. Clear build cache: Site Settings → Danger Zone → Clear cache and deploy site
4. Redeploy: netlify deploy --prod or push to git
5. Verify: Check function logs in Netlify UI (Functions tab)
⚠️ Version Note: Behavior changed between Netlify CLI v12 and v13 (2024-2025). If using older CLI, upgrade with npm install -g netlify-cli@latest.
---
Still Broken? Check These Too
1. Function timeout before env loads – Increase timeout in netlify.toml: [functions] timeout = 30 (default is 10s). See [Netlify function timeouts guide](/?guide=function-timeout).
2. Using Next.js or SvelteKit? – Framework-specific functions may need vars in netlify/functions/.env.local instead. See [SSR framework env vars](/?guide=ssr-env-vars).
3. Hardcoded secrets in git – Search git history: git log -p --all -S "sk-" -- "*.js". Rotate compromised keys immediately, then use Netlify's encrypted environment variable storage instead.
---
Official Resources
---
Quick Checklist
netlify.toml[functions] section exists in configprocess.env.VAR_NAME, not destructuring at module load---
Found a different variation? Drop it in the comments – If your error looked different or this didn't solve it, post the exact error message and we'll add it to this guide.