Netlify: env vars not loading in functions [2026 fix]
Env vars undefined in Netlify Functions? Redeploy after adding to netlify.toml or UI—Functions cache old builds until deployment.
TL;DR
Cause: Environment variables aren't being injected into your Netlify Functions during build or runtime because they're missing from netlify.toml, the Netlify UI settings, or the function hasn't been redeployed after you added them.
Fix: Add variables to netlify.toml under [functions], commit, push, and trigger a redeploy (or set them in Site Settings → Environment variables).
---
Real Console Error Messages
Here are exact errors you'll see at 2am:
``` TypeError: Cannot read property 'apiKey' of undefined at handler (/var/task/src/functions/api-proxy.js:12:5) ```
``` ReferenceError: process.env.DATABASE_URL is not defined at Object.<anonymous> (/var/task/netlify/functions/db.js:3:1) ```
``` Error: Missing required environment variable: STRIPE_SECRET_KEY at initializeStripe (/var/task/functions/stripe-webhook.js:8:15) ```
``` Warning: Expected env var NEXT_PUBLIC_API_URL but got undefined at runtime in edge function context ```
``` 502 Bad Gateway - Function returned error: Cannot destructure property 'apiSecret' of 'undefined' (reading 'apiSecret') ```
---
Broken Code vs. Exact Fix
Example 1: Missing netlify.toml Configuration
BROKEN: ```toml
netlify.toml (incomplete)
[build] command = "npm run build" publish = "dist" ```FIXED: ```toml
netlify.toml (correct)
[build] command = "npm run build" publish = "dist"[functions] node_bundler = "esbuild"
[[redirects]] from = "/api/*" to = "/.netlify/functions/:splat" status = 200
[env.production] [env.production.functions] DB_URL = "postgresql://user:pass@host/db" API_KEY = "sk_live_xxxxx" STRIPE_SECRET_KEY = "sk_live_yyyyy"
[env.development] [env.development.functions] DB_URL = "postgresql://localhost/testdb" API_KEY = "sk_test_xxxxx" STRIPE_SECRET_KEY = "sk_test_yyyyy" ```
Example 2: Function Accessing Undefined Variables
BROKEN: ```javascript // netlify/functions/api-proxy.js exports.handler = async (event) => { const apiKey = process.env.API_KEY; // undefined! const dbUrl = process.env.DB_URL; // undefined! return { statusCode: 200, body: JSON.stringify({ apiKey, dbUrl }) }; }; ```
FIXED: ```javascript // netlify/functions/api-proxy.js exports.handler = async (event) => { // Explicitly check and provide fallback const apiKey = process.env.API_KEY; const dbUrl = process.env.DB_URL; // Validate at function startup if (!apiKey || !dbUrl) { console.error("Missing env vars:", { apiKey: !!apiKey, dbUrl: !!dbUrl }); return { statusCode: 500, body: JSON.stringify({ error: "Configuration error" }) }; } // Safe to use now return { statusCode: 200, body: JSON.stringify({ success: true }) }; }; ```
Example 3: UI-Only Configuration (No netlify.toml)
BROKEN (incomplete workflow):
1. Add vars in Netlify UI: Settings → Environment variables
2. Deploy without committing netlify.toml
3. Functions still can't access them
FIXED (complete workflow):
1. Add to netlify.toml (version-controlled)
2. OR add to Netlify UI AND ensure your build hook redeploys
3. For build-time vars: prefix with NEXT_PUBLIC_ or VITE_ depending on framework
4. For function-only vars: use [functions] section in netlify.toml
5. Critical: Trigger manual redeploy after changes (don't rely on auto-deploys catching env var updates)
---
Still Broken? Check These Too
1. Wrong environment context – You set vars for [env.production] but deployed to preview/staging branch. Netlify doesn't apply production env vars to preview deployments by default. Solution: Check Site Settings → Environment variables and set them at the root level (applies to all deploys) or explicitly configure branch-specific contexts in netlify.toml.
2. Edge Functions vs. Standard Functions – Edge Functions run in Deno runtime and can't access process.env the same way. Use Deno.env.get() instead. See [Edge Functions Environment Variables](https://docs.netlify.com/edge-functions/overview/) for details.
3. Stale deployment cache – Functions may be cached from 6+ hours ago. Solution: Hard redeploy by going to Site Settings → Builds & deploys → trigger "Deploy site" (not just pushing code). Or use [related guide on Netlify cache invalidation](/?guide=netlify-cache-busting).
4. Function cold start timing – Vars load on cold start; warm containers reuse old values. If you updated env vars 30 seconds ago and hit the function, the old container answered. Wait 5 minutes or clear caches.
5. Missing netlify.toml entirely in subdirectory – If using monorepo, ensure netlify.toml is at repo root, not in a subdirectory. See [related guide on monorepo setup](/?guide=netlify-monorepo).
---
Official Docs
Must-read: [Netlify Functions Environment Variables](https://docs.netlify.com/functions/overview/) – Official docs on both build-time and runtime configuration.
Also helpful: [Netlify Build Environment Variables](https://docs.netlify.com/configure-builds/environment/) – Distinction between build context and function runtime context.
---
Version Notes
I'm fairly confident about netlify.toml [functions] section behavior as of 2024–2026, but Netlify occasionally changes how preview deploys inherit environment variables. If you're on a Netlify plan older than 2023, the [env.*] context syntax may differ. Check your Netlify UI version and cross-reference with official docs above.
---
Found a different variation? Drop it in the comments—include your error message and we'll add it to this guide.