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
| Message | Cause | Fix |
|---|---|---|
$ is not defined | jQuery script not loaded / loaded late | reorder or fix the script tag |
require is not defined | CommonJS code shipped to the browser | bundle it, or use import |
process is not defined | Node global used in client code | use the bundler's client env API |
| a var from another script | module scope isn't shared | export/import explicitly |
| works locally, not in prod | a script failed to load (404/CSP) | check the Network tab for that request |
Debugging checklist
- ✓ Check spelling/case — JavaScript identifiers are case-sensitive
- ✓ Confirm the declaring script/import runs, and runs before, this line
- ✓ Check the Network tab — did that script actually load (200, not 404)?
- ✓ Using
require/processin browser code? Those are Node-only - ✓ Split across
<script type="module">tags? Export/import explicitly - ✓ TypeScript flags most of this at compile time before you ever run the code
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.