globalThis
Refers to the global object in any JavaScript environment, without environment sniffing.
globalThis- Added in JavaScript ECMAScript 2020
Return value
objectThe global this value. In browsers it is a Proxy around the real global object; in Node.js and most other runtimes it is the global object directly.
Changelog
- PHP ECMAScript 2020Standardised, replacing the environment-specific window, self and global. Property attributes: writable yes, enumerable no, configurable yes.
globalThis is the one expression that names the global object everywhere: window in a page, self in a worker, global in Node, and the sandbox global in everything else. Before ES2020 library authors reached for a chain of typeof checks or the Function("return this")() trick; globalThis replaces both.
What it is for
- Feature detection that works in every runtime:
typeof globalThis.fetch === "function"rather than testingwindow. - Installing a polyfill in a way that does not assume a browser.
- Library code that must run unchanged in a page, a worker and a server.
What it is not
It is not a general-purpose namespace. Assigning to it creates a global that is visible to every script in the realm, which is how name collisions and leaks start. Module-scoped variables are almost always the right answer; globalThis is for the small set of cases where the global object genuinely is the target.
Two details
In browsers it is a Proxy around the real global for cross-origin reasons, so identity comparisons against a different realm's global will not match. Modules and functions in strict mode have this as undefined at the top level, so globalThis is the only way to reach the global object from there.
Example
When to use it
- Detect whether an API exists in code that runs in both a browser and a server runtime.
- Install a polyfill onto the global object from a shared library.
- Reach the global object from inside an ES module, where top-level this is undefined.
Frequently asked questions
What is the difference between globalThis and window?
globalThis names the global object in every runtime, while window exists only in a browser page — it is undefined in a worker and absent in Node.js. In a browser they refer to the same object, so globalThis is a safe drop-in that also works everywhere else.
Can I assign to globalThis?
You can assign properties to it, and the binding itself is writable and configurable, so it can even be overwritten. Adding properties is legitimate for polyfills but creates realm-wide globals, so prefer module scope for ordinary values.
Why is globalThis undefined in my environment?
Because the runtime predates ES2020 — it landed in browsers in January 2020 and in Node.js 12. Either raise the baseline or ship the standard shim that falls back through self, window and global.
More examples
Portable feature detection
One lookup answers the question in every runtime. The legacy branch below shows the chain of typeof guards that libraries used to carry, each of which throws a ReferenceError if written without the typeof guard.
function has(name) {
return typeof globalThis[name] === "function";
}
for (const api of ["fetch", "structuredClone", "queueMicrotask", "nope"]) {
console.log(api, has(api));
}
// The pre-ES2020 dance this replaces
const legacy =
typeof window !== "undefined" ? "window"
: typeof self !== "undefined" ? "self"
: "global";
console.log("legacy detection picked:", legacy);Installing a polyfill correctly
defineProperty with enumerable false matches how built-in globals are defined, so the addition does not show up in enumeration. A plain assignment would create an enumerable property, which is visible to code that walks the global object.
if (typeof globalThis.groupBy !== "function") {
Object.defineProperty(globalThis, "groupBy", {
value: (items, fn) => {
const out = {};
for (const it of items) (out[fn(it)] ??= []).push(it);
return out;
},
writable: true,
configurable: true,
enumerable: false, // keep it out of for...in
});
}
console.log(groupBy([1, 2, 3, 4], (n) => (n % 2 ? "odd" : "even")));Global scope versus module scope
Only var declarations in a classic script and explicit assignments become properties of the global object; let and const never do. Properties added by assignment are configurable, so they can be deleted, whereas a var binding cannot.
var legacyVar = 1;
let blockScoped = 2;
// In a classic script, var creates a property on the global object; let does not
console.log("legacyVar on global:", "legacyVar" in globalThis);
console.log("blockScoped on global:", "blockScoped" in globalThis);
globalThis.explicit = 3;
console.log("explicit on global:", "explicit" in globalThis, explicit);
delete globalThis.explicit;
console.log("after delete:", "explicit" in globalThis);
Discussion