Fix TypeError: TypeError: Cannot read properties of undefined (reading 'NEXT_PUBLIC_API_URL') in Next.js
This error occurs when a Next.js environment variable is undefined because it is missing the NEXT_PUBLIC_ prefix for client-side access, or the .env file is not loaded. Server-side env vars are not bundled into client code. Fix it by adding the NEXT_PUBLIC_ prefix or moving the logic to a server component or API route.
Reading the Stack Trace
Here's what each line means:
- at ApiClient (webpack-internal:///./src/lib/api.ts:5:42): The API client at line 5 tries to read process.env.NEXT_PUBLIC_API_URL but it is undefined in the client bundle.
- at fetchUsers (webpack-internal:///./src/hooks/useUsers.ts:8:23): The useUsers hook calls the API client, passing the undefined URL through the call chain.
- at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:16305:18): React is rendering the component with hooks when the undefined variable causes the crash.
Common Causes
1. Missing NEXT_PUBLIC_ prefix
The environment variable is defined without the NEXT_PUBLIC_ prefix, so Next.js does not include it in the client bundle.
// .env.local
API_URL=https://api.example.com
// src/lib/api.ts
const baseUrl = process.env.API_URL; // undefined on client
2. .env file not in project root
The .env file exists but is in the wrong directory. Next.js only reads .env files from the project root.
// .env is in src/.env instead of project root
// src/.env
NEXT_PUBLIC_API_URL=https://api.example.com
3. Server restart needed after env change
Environment variables were added to .env.local but the development server was not restarted, so the new values are not loaded.
// .env.local (just added)
NEXT_PUBLIC_API_URL=https://api.example.com
// Developer forgot to restart next dev
The Fix
Rename the environment variable with the NEXT_PUBLIC_ prefix so Next.js inlines it into the client bundle at build time. Add a runtime check that throws a descriptive error if the variable is missing, making misconfiguration easier to diagnose.
// .env.local
API_URL=https://api.example.com
// src/lib/api.ts
const baseUrl = process.env.API_URL;
export async function fetchUsers() {
const res = await fetch(`${baseUrl}/users`);
return res.json();
}
// .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
// src/lib/api.ts
const baseUrl = process.env.NEXT_PUBLIC_API_URL;
if (!baseUrl) {
throw new Error('NEXT_PUBLIC_API_URL environment variable is not set');
}
export async function fetchUsers() {
const res = await fetch(`${baseUrl}/users`);
return res.json();
}
Testing the Fix
import { fetchUsers } from '@/lib/api';
describe('fetchUsers', () => {
const originalEnv = process.env;
beforeEach(() => {
process.env = { ...originalEnv, NEXT_PUBLIC_API_URL: 'https://api.example.com' };
});
afterEach(() => {
process.env = originalEnv;
});
it('fetches users from the configured API URL', async () => {
global.fetch = jest.fn().mockResolvedValue({
json: () => Promise.resolve([{ id: 1, name: 'Alice' }]),
});
const users = await fetchUsers();
expect(fetch).toHaveBeenCalledWith('https://api.example.com/users');
expect(users).toHaveLength(1);
});
it('throws if NEXT_PUBLIC_API_URL is not set', () => {
delete process.env.NEXT_PUBLIC_API_URL;
expect(() => require('@/lib/api')).toThrow('NEXT_PUBLIC_API_URL');
});
});
Run your tests:
npm test
Pushing Through CI/CD
git checkout -b fix/env-variable-prefix,git add .env.local src/lib/api.ts src/lib/__tests__/api.test.ts,git commit -m "fix: add NEXT_PUBLIC_ prefix to client-side env variable",git push origin fix/env-variable-prefix
Your CI config should look something like this:
name: CI
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
env:
NEXT_PUBLIC_API_URL: https://api.example.com
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm test -- --coverage
- run: npm run build
The Full Manual Process: 18 Steps
Here's every step you just went through to fix this one bug:
- Notice the error alert or see it in your monitoring tool
- Open the error dashboard and read the stack trace
- Identify the file and line number from the stack trace
- Open your IDE and navigate to the file
- Read the surrounding code to understand context
- Reproduce the error locally
- Identify the root cause
- Write the fix
- Run the test suite locally
- Fix any failing tests
- Write new tests covering the edge case
- Run the full test suite again
- Create a new git branch
- Commit and push your changes
- Open a pull request
- Wait for code review
- Merge and deploy to production
- Monitor production to confirm the error is resolved
Total time: 30-60 minutes. For one bug.
Or Let bugstack Fix It in Under 2 minutes
Every step above? bugstack does it automatically.
Step 1: Install the SDK
npm install bugstack-sdk
Step 2: Initialize
import { initBugStack } from 'bugstack-sdk'
initBugStack({ apiKey: process.env.BUGSTACK_API_KEY })
Step 3: There is no step 3.
bugstack handles everything from here:
- Captures the stack trace and request context
- Pulls the relevant source files from your GitHub repo
- Analyzes the error and understands the code context
- Generates a minimal, verified fix
- Runs your existing test suite
- Pushes through your CI/CD pipeline
- Deploys to production (or opens a PR for review)
Time from error to fix deployed: Under 2 minutes.
Human involvement: zero.
Try bugstack Free →No credit card. 5-minute setup. Cancel anytime.
Deploying the Fix (Manual Path)
- Rename the environment variable in .env.local with the NEXT_PUBLIC_ prefix.
- Restart the development server to load the new variable.
- Open a pull request with the env variable and code changes.
- Wait for CI checks to pass on the PR.
- Merge to main and verify the variable is set in the deployment environment.
Frequently Asked Questions
BugStack validates that the environment variable is accessible in both server and client contexts, runs your test suite, and confirms the build succeeds before marking it safe.
Every fix is delivered as a pull request with full CI validation. Your team reviews and approves before anything reaches production.
NEXT_PUBLIC_ variables are embedded in the client bundle and visible to anyone. Only use this prefix for values that are safe to expose publicly, never for secrets or API keys.
NEXT_PUBLIC_ variables are inlined at build time, not runtime. You must set them before running next build. For Vercel, configure them in the project settings dashboard.