Global variable in JavaScript: globalThis, var, strict mode, and multiple files

javascript global variable across files, javascript global variable, js global variable, global variable javascript, global variable in javascript, global var in javascript, var global js, var global javascript, global var javascript, global variable in js: globalThis, strict mode, ES modules, Node.

Published

Updated

Read time 5 min read

Reviewed byDeepak Prasad

Global variable in JavaScript: globalThis, var, strict mode, and multiple files

Global bindings are properties on the shared global object—globalThis in modern code—rather than a separate “global variable” keyword. Accidental globals from bare assignments were common in old scripts, but strict mode (and ES modules, which are strict by default) throw when you assign to an undeclared identifier, which nudges teams toward let/const, explicit exports, and deliberate globalThis namespacing. Default to explicit globalThis when you truly need a cross-script handle in the browser, keep module graphs explicit with import / export, and remember that strict mode rejects accidental globals created by assigning to an undeclared identifier. When import fails in a classic script, the fix is usually a module graph or bundler change—see cannot use import statement outside a module.

Tested on: Node.js v20.18.2. A short note after each runnable snippet describes what you should see in the console.


Put data on globalThis deliberately

globalThis is the interoperable name for the global object in browsers, Node, workers, and embedded runtimes. Assigning a property is the clearest pattern when you control the name and accept the collision risk:

javascript
globalThis.__gvArticleDemo = 2026;
console.log(globalThis.__gvArticleDemo);
Reflect.deleteProperty(globalThis, "__gvArticleDemo");
Output

You should see one line logging 2026.

In browsers you can still read window on the main thread, but globalThis reads the same object there and stays portable.


var inside a block versus let

var is function-scoped (or script-scoped), so a var inside a block still exists after the block ends. let stays block-scoped, so the same pattern throws when you leave the block:

javascript
(function () {
  {
    let another = 23;
    var newOne = 23;
  }
  console.log(newOne);
  try {
    console.log(another);
  } catch (e) {
    console.log(e.name);
  }
})();
Output

You should see 2 lines, in order: 23, ReferenceError.

That is why modern code prefers let / const for locals: it narrows visibility without relying on hoisting rules.


Strict mode blocks implicit globals

In strict functions—and in JavaScript modules strictness is automatic—assigning to a name that was never declared is a ReferenceError, not a silent global:

javascript
try {
  (function () {
    "use strict";
    __gvStrictLeak = 1;
  })();
} catch (e) {
  console.log(e.name);
}
Output

You should see one line logging ReferenceError.


Sloppy-mode implicit globals (avoid in new code)

Without strict mode, assigning to an undeclared identifier creates a property on the global object. The snippet below uses new Function so the assignment runs in a non-strict body even when the surrounding file is strict (the same technique used in automated tests):

javascript
const g = new Function("__gvSloppyLeak = 7;");
g();
console.log(globalThis.__gvSloppyLeak);
Reflect.deleteProperty(globalThis, "__gvSloppyLeak");
Output

You should see one line logging 7.

Do not rely on this pattern in application code; it hides typos and collides across third-party scripts.


vm.runInThisContext and classic “eval” globals in Node

In Node, a normal .cjs file wraps top-level declarations in a module function, so a top-level var in that file is not automatically a globalThis property (unlike a browser <script> without type="module"). Legacy code that expected true globals sometimes used vm.runInThisContext, which executes a string like a script body on the current globalThis:

javascript
const vm = require("vm");

vm.runInThisContext("var __gvVmVar = 123");
console.log(globalThis.__gvVmVar);
Reflect.deleteProperty(globalThis, "__gvVmVar");
Output

You should see one line logging 123.

Prefer export / import or explicit globalThis.myNamespace = {...} over scattering var through eval-like paths.


let at the top level is not a globalThis own property

Top-level let / const create module or script bindings; they do not define enumerable properties on globalThis the way var does in a sloppy browser script:

javascript
const hasZ = new Function(`
  "use strict";
  let z = 1;
  return Object.prototype.hasOwnProperty.call(globalThis, "z");
`)();
console.log(hasZ);
Output

You should see one line logging false.


javascript global variable across files

Across files you have three sane options:

  1. ES modules: declare export const api = {...} in one file and import { api } from "./api.js" elsewhere. Nothing is “global” except the module namespace object the loader gives you.
  2. Bundlers still resolve to modules; avoid leaking to window unless you intentionally support a plugin host page.
  3. When you must bridge legacy scripts, attach one namespace object: globalThis.MyApp = globalThis.MyApp || {}; and hang helpers from it, instead of dozens of loose identifiers.

Why globals are risky

Shared globals are easy targets for name collisions between your code, analytics snippets, and extensions; they complicate testing because every test shares the same mutable bag; and they hide data flow. Reach for globals only at integration boundaries (for example a single namespace on globalThis), not as your default state store.


Summary

Javascript global variable confusion usually splits into browser sloppy-mode var hoisting, ES module top-level bindings that are not globalThis properties, and intentional globalThis namespaces for legacy bridges. The recurring FAQ is whether let at the top level shows up on window—in modern browsers it does not, which is why feature detection should use globalThis or window explicitly when you mean the real global object.

Across files, prefer modules (import / export) or bundler equivalents instead of scattering identifiers; when you must share state, attach one well-named object to globalThis rather than dozens of loose globals that collide with analytics snippets or user extensions. Understanding strict versus sloppy scripts still matters when you maintain older <script> tags without type="module".


References

Olorunfemi Akinlua

Boasting over five years of experience in JavaScript, specializing in technical content writing and UX design. With a keen focus on programming languages, he crafts compelling content and designs …