Netlify: env vars not loading in functions [2026 fix]
Env vars fail in Netlify Functions because they're not bundled into the function package. Move vars to netlify.toml [functions] or use context.clientContext.
TL;DR
Cause: Environment variables defined in Netlify UI aren't automatically injected into serverless Functions; they're only available at build-time unless explicitly configured.
Fix: Define function-specific env vars in netlify.toml under [functions] section or access them via context.clientContext in newer runtimes.
---
Real Console Error Messages
``` 1. TypeError: Cannot read properties of undefined (reading 'DATABASE_URL') at Runtime.handler (/var/task/index.js:15:23)
2. ReferenceError: STRIPE_API_KEY is not defined at Object.<anonymous> (/var/task/functions/stripe.js:3:5)
3. Error: env var SECRET_TOKEN returned undefined in function execution at checkEnv (/var/task/middleware.js:42:10)
4. Uncaught SyntaxError: Invalid or unexpected token at process.env.API_URL Context: function logs show 'undefined' when accessing process.env
5. TypeError: Cannot set property AUTH_SECRET, which has only a getter indicates immutable env state in Netlify Functions container ```
---
The Problem: Broken vs Fixed Code
❌ BROKEN: Relying on UI-defined env vars in Functions
```javascript // netlify/functions/api.js exports.handler = async (event, context) => { const dbUrl = process.env.DATABASE_URL; // ← UNDEFINED const apiKey = process.env.STRIPE_KEY; // ← UNDEFINED const response = await fetch(dbUrl); return { statusCode: 200, body: JSON.stringify({ key: apiKey }) }; }; ```
Result at 2am: Function returns undefined for all env vars despite being set in Netlify dashboard.
---
✅ FIXED: Method 1 – netlify.toml configuration
```toml
netlify.toml
[functions] node_bundler = "esbuild" [[functions]] name = "api" external_node_modules = ["lodash"] environment = { DATABASE_URL = "postgresql://user:pass@host/db", STRIPE_KEY = "sk_live_..." } ``````javascript // netlify/functions/api.js exports.handler = async (event, context) => { const dbUrl = process.env.DATABASE_URL; // ✅ NOW DEFINED const apiKey = process.env.STRIPE_KEY; // ✅ NOW DEFINED const response = await fetch(dbUrl); return { statusCode: 200, body: JSON.stringify({ key: apiKey }) }; }; ```
---
✅ FIXED: Method 2 – context.clientContext (Netlify Runtime v1+)
```javascript // netlify/functions/api.js exports.handler = async (event, context) => { // Access from context injected by Netlify runtime const { DATABASE_URL, STRIPE_KEY } = context.clientContext.custom || {}; if (!DATABASE_URL) { return { statusCode: 500, body: JSON.stringify({ error: "DATABASE_URL not found in context" }) }; } const response = await fetch(DATABASE_URL); return { statusCode: 200, body: JSON.stringify({ key: STRIPE_KEY }) }; }; ```
Note: context.clientContext approach requires Netlify Functions Runtime v1.0+. If uncertain about your runtime version, check your netlify.toml for aws_lambda_memory or test locally with netlify dev.
---
✅ FIXED: Method 3 – Secrets via Build Context (TypeScript example)
```typescript // netlify/functions/secure.ts import { Handler, HandlerContext } from "@netlify/functions";
const handler: Handler = async (event, context: HandlerContext) => { // For secrets, prefer netlify.toml [functions] block // Avoid logging sensitive data const hasToken = !!process.env.AUTH_SECRET; return { statusCode: 200, body: JSON.stringify({ authenticated: hasToken }) }; };
export { handler }; ```
---
Still Broken? Check These Too
1. Build cache issue – Netlify might be serving stale function bundles. Go to Deploy Settings → Trigger Deploy → "Deploy site" (not "Clear cache and deploy" first, that's often ineffective). Wait 2–3 minutes for Functions to redeploy.
2. Function bundling mismatch – If using a custom build command, ensure node_bundler = "esbuild" is set in netlify.toml. Older zisi bundler doesn't always pick up env vars correctly. See [Netlify build environment setup](/?guide=build-env) for details.
3. Scope confusion: Build vs Runtime – Env vars in Netlify UI apply at *build time* (for Next.js, Hugo, etc.). Functions need *runtime* vars. These are two separate systems. Double-check you're not confusing process.env in build scripts with process.env in function handlers. See [environment variables in Netlify functions](/?guide=netlify-function-env) for comparison.
---
Debugging Checklist
netlify dev --clearnetlify.toml has correct [[functions]] block (note double brackets)netlify.toml or passed explicitly)netlify dev loads env from .env file in project root---
Official Resources
---
Found a different variation? Drop it in the comments – If you hit a unique error or discovered another cause (Docker layer caching, monorepo-specific issues, region-based behavior), let us know and we'll add it to this guide.