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

Netlify functions can't access env vars because they're not deployed in netlify.toml or using legacy config. Deploy with netlify.toml [functions] section.

Netlify: Environment Variables Not Loading in Functions

TL;DR

Cause: Your environment variables are set in Netlify UI but not declared in netlify.toml under [functions], or you're using legacy function deployment without proper config.

Fix: Add environment = { VAR_NAME = "value" } to your netlify.toml [functions] section and redeploy—UI-only vars don't auto-inject into serverless functions.

---

Real Console Error Messages

Here are the exact errors you'll see in your 2am panic:

``` Uncaught ReferenceError: process.env.DATABASE_URL is not defined at handler (/var/task/functions/api.js:5:3) ```

``` Error: STRIPE_SECRET_KEY is undefined. Check your environment configuration. at Object.<anonymous> (functions/payments.js:1) ```

``` TypeError: Cannot read property 'split' of undefined at getApiKey (functions/auth.js:12:3) [process.env.API_KEY is undefined] ```

``` Netlify Functions runtime error: Missing required environment variable MESSAGE: Cannot find API_URL in function scope ```

``` FunctionError: Your function returned an error: TypeError: database_host is undefined CAUSED BY: process.env.database_host was not injected at runtime ```

---

Broken Code vs. Fix

❌ BROKEN: Environment vars in UI only

```javascript // netlify.toml - INCOMPLETE [build] command = "npm run build" functions = "netlify/functions"

// functions/api.js exports.handler = async (event) => { const dbUrl = process.env.DATABASE_URL; // ❌ UNDEFINED - only set in UI const stripe = require('stripe')(process.env.STRIPE_KEY); // ❌ NULL return { statusCode: 500, body: 'Vars not loaded' }; }; ```

✅ FIXED: Declare vars in netlify.toml

```toml

netlify.toml - CORRECT

[build] command = "npm run build" functions = "netlify/functions"

[functions] environment = { DATABASE_URL = "postgresql://user:pass@host/db", STRIPE_KEY = "sk_live_abc123", LOG_LEVEL = "debug" } ```

```javascript // functions/api.js - NOW WORKS exports.handler = async (event) => { const dbUrl = process.env.DATABASE_URL; // ✅ "postgresql://user:pass@host/db" const stripe = require('stripe')(process.env.STRIPE_KEY); // ✅ "sk_live_abc123" return { statusCode: 200, body: JSON.stringify({ status: 'connected' }) }; }; ```

---

Why This Happens

Netlify UI environment variables are available to build processes and site context but not automatically injected into serverless function runtime unless you:

1. Define them in netlify.toml [functions] block (recommended for production) 2. Use Netlify's environment variable injection API (for dynamic values) 3. Set them per-function with individual config files (for granular control)

This is a security boundary: functions get explicit variable allowlists to prevent accidental secret leakage.

---

Step-by-Step Fix

Step 1: Open your netlify.toml at project root

Step 2: Add or update the [functions] section:

```toml [functions] environment = { DATABASE_URL = "your_actual_value", API_KEY = "sk_test_xyz" } ```

Step 3: For sensitive secrets, use Netlify's UI Settings > Build & Deploy > Environment variables, then reference them in netlify.toml:

```toml

Set these in UI, they'll be available as $VAR_NAME in netlify.toml

[functions] environment = { SECRET = "$SECRET_FROM_UI" } ```

Step 4: Commit and push:

```bash git add netlify.toml git commit -m "fix: add env vars to functions config" git push origin main ```

Step 5: Netlify redeploys automatically—check Deployments tab for completion (2-5 min)

Step 6: Test your function:

```bash curl https://your-site.netlify.app/.netlify/functions/api

Should return 200, not undefined errors

```

---

Still Broken? Check These Too

1. Function naming mismatch: File is api.js but you're calling .netlify/functions/api-handler? Netlify function routes match filenames exactly (minus .js). Rename files to match your routes. See [Netlify function routing guide](/?guide=netlify-function-routing).

2. Build-time vs. runtime confusion: Variables used *during build* (Next.js, Gatsby) need NEXT_PUBLIC_* prefix for client exposure. Backend function vars use plain PROCESS_ENV. Don't mix them. Check [environment variable scoping](/?guide=env-var-scope).

3. Stale function cache: Netlify caches old function builds. Clear it by navigating to Deploys > trigger deploy or delete .netlify folder and rebuild locally with netlify build && netlify deploy.

---

Official Docs

[Netlify Functions Environment Variables Documentation](https://docs.netlify.com/functions/overview/#environment-variables)

[netlify.toml Reference](https://docs.netlify.com/configure-builds/file-api-reference/)

---

Version Notes

This fix applies to Netlify Functions on any runtime (Node 18+, Python, Go). Behavior is consistent as of 2026. If you're using Netlify Edge Functions (edge compute), variables are accessed the same way but deployed with different syntax—[check Edge Functions docs](https://docs.netlify.com/edge-functions/overview/) if .netlify/functions isn't your deployment target.

---

Found a different variation? Drop it in the comments—did you hit this with a specific framework (Next.js, Remix, SvelteKit) or a different error message? Let us know so we can expand this guide.

🔥 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