Uncaught ReferenceError: X is not defined

Quick answer

JavaScript searched every scope up to global and found no variable named X anywhere. Unlike "cannot read properties," this isn't about a value being empty — X was never declared where this code can see it. The usual causes: a typo/case mismatch, a script that hasn't loaded yet (or at all), or code assuming a Node global (require, process) that doesn't exist in the browser.

The exact error string

console.log(totalPrice);
// Uncaught ReferenceError: totalPrice is not defined

$(".menu").toggle();
// Uncaught ReferenceError: $ is not defined
//   -> jQuery's <script> tag never loaded, or loads after this line

How to diagnose it in 30 seconds

First check spelling and case — JavaScript is case-sensitive, so userName and username are different identifiers. If the name looks right, the identifier is either never declared, or declared somewhere this code can't reach: a script that loads later, a different module's top-level scope, or a block scope ({ }) that ended before this line runs.

Cause 1: script load order

<!-- ❌ your code runs before jQuery has loaded -->
<script src="app.js"></script>
<script src="https://code.jquery.com/jquery.min.js"></script>

<!-- ✅ dependency first -->
<script src="https://code.jquery.com/jquery.min.js"></script>
<script src="app.js"></script>

Cause 2: the script failed to load at all

Open the Network tab: a 404, a blocked request (ad blocker, CSP), or a typo'd src path all mean the file that would have declared X never ran. The reference error shows up wherever X is later used, not at the broken <script> tag itself.

Cause 3: Node globals in browser code

const fs = require("fs");
// ❌ Uncaught ReferenceError: require is not defined (require is Node-only)

console.log(process.env.API_URL);
// ❌ Uncaught ReferenceError: process is not defined (process is Node-only)

// ✅ in a bundled app, use ESM import syntax and the bundler's env mechanism:
import { readFile } from "some-browser-safe-lib";
console.log(import.meta.env.VITE_API_URL);   // Vite's client-exposed env

Cause 4: module scope isn't shared

<!-- config.js -->
<script type="module">
  const apiUrl = "https://api.example.com";
</script>

<!-- app.js -->
<script type="module">
  console.log(apiUrl);
  // ❌ apiUrl is not defined — each module has its own top-level scope
</script>

<!-- ✅ export it explicitly and import where needed -->
<!-- config.js -->  export const apiUrl = "https://api.example.com";
<!-- app.js   -->  import { apiUrl } from "./config.js";

Common variants at a glance

MessageCauseFix
$ is not definedjQuery script not loaded / loaded latereorder or fix the script tag
require is not definedCommonJS code shipped to the browserbundle it, or use import
process is not definedNode global used in client codeuse the bundler's client env API
a var from another scriptmodule scope isn't sharedexport/import explicitly
works locally, not in proda script failed to load (404/CSP)check the Network tab for that request

Debugging checklist

Frequently Asked Questions

What does 'X is not defined' mean?

JavaScript looked up the identifier X through every enclosing scope, all the way to the global scope, and found no variable, function, or class by that name declared anywhere reachable. This is different from a value being null or undefined — here the name itself was never declared in any scope the engine could see.

Why does a library like jQuery say it's not defined?

The <script> tag that loads the library either wasn't included, is loaded after your code runs, or failed to load (404, blocked, wrong path). Check the Network tab for the script's request, and make sure library <script> tags appear before the code that uses the global they define.

Why does 'require is not defined' happen in the browser?

require is a Node.js/CommonJS global — browsers don't have it natively. This happens when server-side (CommonJS) code is shipped straight to the browser without bundling, or an ES module file accidentally uses require instead of import. Use a bundler (webpack/Vite/esbuild) or switch to import syntax.

Why does 'process is not defined' happen outside Node?

process is a Node.js global; it doesn't exist in the browser. This is common when frontend code reads process.env.X the way server code does — in bundlers like Vite, use their client-exposed env mechanism (e.g. import.meta.env) instead of assuming process is available.

Why is a variable from another <script> tag not defined?

Each ES module has its own scope — a top-level variable in one <script type="module"> is not automatically visible in another. Classic (non-module) scripts do share the global scope, so mixing module and non-module scripts is a common source of this. Export/import explicitly, or attach the value to window if you need a true global.

How do I fix 'X is not defined' fast?

Check spelling and case first (JavaScript is case-sensitive). Then confirm the declaring script/import actually runs before this line, and that it isn't scoped somewhere this code can't see (a different module, a block scope with let/const, or a script that failed to load).

More JavaScript & runtime errors

Browse the full reference for JavaScript, Node.js, and database errors — exact message, cause, and fix.

All Error References Cannot access 'X' before initialization HTTP Status Codes
About the author

Pasindu Ishan is a software developer based in Sri Lanka. He builds privacy-first developer tools at JSON Dev Tools.