Netlify: env vars not loading in functions [2026 fix]

Env vars undefined in Netlify Functions? Deploy without netlify.toml config or use wrong path syntax—redeploy after fixing.

TL;DR

Cause: Environment variables aren't being passed to serverless functions because your netlify.toml is missing the [functions] configuration block or your function can't find .env files at build time.

Fix: Add directory = "netlify/functions" to netlify.toml and ensure env vars are set in Netlify dashboard (not just local .env), then redeploy.

---

Real Console Error Messages

``` Error: Cannot find module 'undefined' at Function.Module._resolveFilename ```

``` TypeError: process.env.STRIPE_KEY is undefined when calling Stripe API ```

``` netlify dev: Function loaded but env vars are null in handler ```

``` ReferenceError: NEXT_PUBLIC_API_URL is not defined inside function scope ```

``` 502 Bad Gateway - function crashed due to missing DATABASE_URL environment variable ```

---

Broken Code vs. Fix

Problem 1: Missing netlify.toml Configuration

BROKEN: ```toml [build] command = "npm run build" publish = ".next/out"

No [functions] block!

```

FIXED: ```toml [build] command = "npm run build" publish = ".next/out"

[functions] directory = "netlify/functions" node_bundler = "esbuild" ```

---

Problem 2: Accessing Env Vars Wrong Way in Function

BROKEN: ```javascript // netlify/functions/api.js exports.handler = async (event, context) => { // Trying to use env var before it's loaded const apiKey = process.env.API_KEY; // undefined! return { statusCode: 200, body: JSON.stringify({ key: apiKey }) }; }; ```

FIXED: ```javascript // netlify/functions/api.js exports.handler = async (event, context) => { // Explicitly destructure from process.env inside handler const { API_KEY } = process.env; if (!API_KEY) { return { statusCode: 500, body: JSON.stringify({ error: "API_KEY not configured" }) }; } return { statusCode: 200, body: JSON.stringify({ key: API_KEY }) }; }; ```

---

Problem 3: Local .env Not Deployed

BROKEN: ```bash

.env (local only, never deployed)

DATABASE_URL=postgres://user:pass@localhost:5432/db API_SECRET=my_secret_key ```

FIXED: ``` 1. Delete .env from production tracking 2. Go to Netlify Dashboard → Site Settings → Build & Deploy → Environment 3. Add each variable manually: - Key: DATABASE_URL - Value: postgres://prod_user:prod_pass@prod_host/db - Key: API_SECRET - Value: my_production_secret 4. Redeploy: push to git or manually trigger deploy ```

---

Problem 4: Next.js NEXT_PUBLIC_ Prefix Confusion

BROKEN: ```javascript // netlify/functions/auth.js const publicUrl = process.env.NEXT_PUBLIC_API_URL; // undefined in function const secret = process.env.API_SECRET; // might also be undefined ```

FIXED: ```javascript // netlify/functions/auth.js // NEXT_PUBLIC_ vars are for client-side only, avoid in functions const secret = process.env.API_SECRET; // server-side only

// If you need public URL, set it as regular env var too: const publicUrl = process.env.PUBLIC_API_URL || process.env.NEXT_PUBLIC_API_URL;

// Better: set API_URL as non-public var for functions exports.handler = async (event) => { const apiSecret = process.env.API_SECRET; const apiUrl = process.env.API_URL; // not NEXT_PUBLIC_ return { statusCode: 200 }; }; ```

---

Why This Happens at 2am

You pushed code locally tested with .env file, but Netlify Functions run in isolated serverless containers that never see your local .env. Only vars set in the Netlify dashboard get injected. Redeploy after adding them (even without code changes).

Uncertainty note: Netlify Functions behavior with environment variables changed slightly between 2024-2026. If you're using @netlify/functions package (newer approach), check official docs below for exact syntax for your version.

---

Still broken? Check these too

1. Env vars set AFTER deploy started — If you added env vars to dashboard, redeploy by pushing to git. Builds in progress won't see new vars. Check Deploy settings → "Trigger deploy" button.

2. Using require() at module level — Some modules try to read env vars when imported. Move require('dotenv').config() inside your handler function, not top-level, [see Lambda env best practices](/?guide=lambda-env).

3. Branch deploys vs. production — Preview branches might use different env var settings. Check Netlify Dashboard → Deploy settings → Environment. Set context-specific vars if needed: ```toml [context.deploy-preview] environment = { API_URL = "https://staging.example.com" } ```

---

Quick Verification Checklist

  • [ ] Env var exists in Netlify Dashboard (not just local .env)
  • [ ] netlify.toml has [functions] block with directory set
  • [ ] Redeploy after changing env vars
  • [ ] Check function logs: Netlify → Functions → click function name → Logs
  • [ ] Ensure no typos in variable names (case-sensitive)
  • [ ] If using netlify dev, restart it after changing .env
  • ---

    Official Resources

  • [Netlify Functions Environment Variables Guide](https://docs.netlify.com/functions/overview/?fn-language=ts#access-environment-variables)
  • [Netlify.toml Reference](https://docs.netlify.com/configure-builds/file-api-reference/#functions)
  • ---

    Found a different variation? Drop it in the comments. Include your error message and netlify.toml snippet so we can add it here.

    🔥 0d
    LIVE
    PlanetScale rage spiking Vercel pricing complaints Railway gaining fast Supabase happiness rising Resend loved by devs PlanetScale rage spiking Vercel pricing complaints Railway gaining fast Supabase happiness rising
    DEVELOPER PAIN RADAR // Loading...

    Developers complain.
    Opportunities appear.

    We track what developers are struggling with today — and what opportunities that creates.

    guides today
    avg happiness
    🔥 Pain
    📖 Guides
    🔭 Explore
    👤 Mine
    🔥 Pain Radar — rage scores today
    ↗ share
    💡 Opportunity Feed — pain = market gap
    📈 Tool Momentum
    all scores →
    📖 Latest Guide
    all guides →
    📖 All Guides
    📊 Tool Scores
    + Submit
    📰 Hacker News
    ➕ Submit a Tool
    ← back