Skip to Content
Course content

249: globalThis Explained

Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you've spent any time writing libraries or utilities that need to run in both the browser and Node.js, you've likely run into the "global object" headache. You want to attach something to the global scope—maybe a configuration object or a telemetry hook—but the global object isn't actually the same thing everywhere. In the browser, it's window. In Node, it's global. If you're inside a Web Worker, it's self. It's a fragmented mess that forces us to write defensive, boilerplate-heavy code just to reference the root of the environment.

The dance of the environment check

For years, the standard "safe" way to handle this was to write a detection utility. You've probably seen this pattern in older open-source projects: a messy ternary operator or a series of if statements trying to guess where the code is currently executing. I used to do this all the time when building cross-platform validators.

const getGlobal = function () {
  if (typeof self !== 'undefined') { return self; }
  if (typeof window !== 'undefined') { return window; }
  if (typeof global !== 'undefined') { return global; }
  throw new Error('Unable to locate global object');
};

const root = getGlobal();
root.myAppConfig = { apiVersion: 'v2' };

Now, this works, but it's fragile. It relies on typeof checks to avoid throwing ReferenceError exceptions when a variable doesn't exist in that specific environment. It's a lot of cognitive load for something that should be a fundamental part of the language. Plus, it's just ugly. You're essentially writing a mini-polyfill for the environment itself before you can even get to your actual logic.

The simplicity of globalThis

This is exactly why globalThis was introduced. It provides a single, standardized property that always points to the global object, regardless of whether you're in a browser, a server, or a worker. No detection logic, no ternary operators, and no worrying about whether window is defined.

// No matter where this runs, it just works.
globalThis.myAppConfig = { apiVersion: 'v2' };

I like to think of globalThis as the "universal adapter" for JavaScript. By using it, you're telling the engine, "I don't care what the environment calls its root; just give me the root." It makes your code cleaner and significantly more portable. If you're writing a module that might be imported into a Vite project (browser) and a Jest test (Node), globalThis is the only sane way to handle global state.

When to actually use it

A word of caution: just because you can easily access the global scope doesn't mean you should be polluting it. In modern development, we prefer modules and dependency injection. However, there are legitimate cases—like creating a global polyfill, setting up a global error handler, or configuring a library that needs to be accessible across multiple bundled chunks—where globalThis is the right tool. When those cases arise, stop writing environment checks and just use the standard.




📋 Practical Task

Refactoring the Cross-Platform Logger

You have been handed a legacy logging utility designed to work in both Node.js and the browser. Currently, it uses a clunky detection function to attach the logger to the global scope. Your task is to refactor this utility to use globalThis, removing the need for the detectGlobal helper function entirely.

// Current Legacy Code
function detectGlobal() {
  if (typeof window !== 'undefined') return window;
  if (typeof global !== 'undefined') return global;
  return typeof self !== 'undefined' ? self : {};
}

const root = detectGlobal();
root.appLogger = {
  log: (msg) => console.log(`[LOG]: ${msg}`),
  error: (msg) => console.error(`[ERROR]: ${msg}`)
};

// Test it
appLogger.log('System initialized');

Goal: Rewrite the code so that the appLogger is attached to the global scope using globalThis in a single line of assignment, eliminating the detectGlobal function.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.