# Beyond window: Understanding global and globalThis in JavaScript

When you wrote your first line of Node.js code, you probably typed `console.log("Hello World")` and it just worked. No import. No setup. Nobody told you where `console` came from, and at the time, it did not matter.

But if you have ever stopped to wonder why `console`, `setTimeout`, and `process` are just... there, ready to use before your code does anything, the answer is `global`. It is the object Node.js quietly builds before your code even starts running, and it holds everything the runtime gives you for free.

Then in 2020, JavaScript introduced `globalThis`, which sounds like a small thing but solved a problem that had been quietly annoying developers for years.

* * *

## What is Node.js, Actually?

JavaScript was built for browsers. Chrome, Firefox, Safari, all of them come with a JavaScript engine and a set of built-in tools like `document`, `window`, and `fetch` that let your code interact with a webpage.

Node.js had a different idea. It took V8, the same engine Chrome uses to run JavaScript, and stripped out everything browser-specific. The result was a JavaScript runtime that could run anywhere: on a server, on your machine, inside a build tool, wherever.

The language is the same. The environment is different. And just like browsers have an object that holds everything your code needs without importing it, Node.js has its own version of that.

In the browser, that object is `window`.

In Node.js, it is `global`.

![](https://cdn.hashnode.com/uploads/covers/678b775e773554ab7117f20a/762ca162-6944-4666-8971-ae25ef45d1d6.png align="center")

* * *

## `global`: The Object That Holds Everything

When Node.js starts up, it creates the `global` object and populates it with every built-in tool your code might need. When you type `console.log()`, Node.js is actually looking up `global.console.log()` behind the scenes.

```js
// What you write:
console.log("I am global");
setTimeout(() => {}, 1000);

// What Node.js actually does:
global.console.log("I am global");
global.setTimeout(() => {}, 1000);
```

Node.js lets you skip the `global.` prefix, so it feels like these things exist on their own. But they are just properties on that one shared object.

```js
console.log(global.console === console);       // true
console.log(global.setTimeout === setTimeout); // true
```

Here is a look at what lives on `global` by default:

| Category | What you get |
| --- | --- |
| Output | `console` |
| Timers | `setTimeout`, `setInterval`, `setImmediate`, `clearTimeout`, `clearInterval` |
| Module system | `require`, `module`, `exports`, `__filename`, `__dirname` |
| Runtime info | `process` |
| Data structures | `Buffer` |
| Async primitives | `Promise` |
| Universal JS | `Math`, `JSON`, `Date`, `Error` |

![](https://cdn.hashnode.com/uploads/covers/678b775e773554ab7117f20a/748db79e-05c1-4319-b8ec-210f284a2a75.png align="center")

* * *

## Why `this` at the Top Level is Not `global`

Here is something that catches a lot of people off guard. If you open a Node.js file and log `this` at the top level, you do not get `global`.

```js
console.log(this);           // {}
console.log(this === global); // false
```

The reason is that Node.js does not actually run your file directly. Before execution, it wraps your entire file in a function:

```js
// Node.js silently does this before running your code:
(function(exports, require, module, __filename, __dirname) {

  // everything you write ends up in here

});
```

So your code is never truly at the top level. It is inside a function, and inside that function, `this` points to `module.exports`, not `global`. `module.exports` starts as an empty object, which is why you see `{}`.

```js
console.log(this);                   // {}
console.log(this === global);        // false
console.log(this === module.exports); // true
```

If you call a regular function (not a method, not in strict mode), `this` inside it does resolve to `global`:

```js
function test() {
  console.log(this === global); // true
}

test();
```

Here is the full picture:

| Where the code runs | What `this` becomes |
| --- | --- |
| Browser top level | `window` |
| Node.js top level | `module.exports` (empty `{}`) |
| Regular function call (non-strict) | `global` |
| Strict mode function | `undefined` |
| Method call | the object the method belongs to |
| Any environment | `globalThis` |

* * *

## The Problem `globalThis` Was Built to Solve

For a long time, Node.js developers used `global` and browser developers used `window`. That was fine until someone needed to write code that ran in both.

Say you build a utility library for formatting dates or handling errors and publish it on npm. Browser apps use it. Node.js apps use it. The moment you try to reference the global object directly, you are stuck:

```js
// Crashes in Node.js
console.log(window.Math);
// ReferenceError: window is not defined

// Crashes in a browser
console.log(global.Math);
// ReferenceError: global is not defined
```

Neither name works in both places. So developers wrote workarounds like this:

```js
const globalObject =
  typeof window !== "undefined" ? window :
  typeof global !== "undefined" ? global :
  typeof self   !== "undefined" ? self   :
  null;
```

It worked, but it was fragile and ugly. Every shared library had its own version of this block.

ES2020 replaced all of that with one thing.

* * *

## `globalThis`: One Name That Works Everywhere

`globalThis` is a standard, universal way to access the global object regardless of where the code is running.

```js
// In Node.js:
console.log(globalThis === global); // true

// In a browser:
console.log(globalThis === window); // true

// In a Web Worker:
console.log(globalThis === self);   // true
```

That messy workaround from above becomes:

```js
const globalObject = globalThis;
```

![](https://cdn.hashnode.com/uploads/covers/678b775e773554ab7117f20a/18355593-a702-47d8-95b1-26e81fa7d6ba.png align="center")

`globalThis` did not replace `global` in Node.js. `global` is still valid and still works. The difference is portability:

| Environment | `global` works | `globalThis` works |
| --- | --- | --- |
| Node.js | Yes | Yes |
| Browser | No | Yes |
| Web Workers | No | Yes |
| Deno | No | Yes |

If you are writing code that will only ever run in Node.js, `global` is fine. If there is any chance your code ends up in a browser or gets shared as a library, use `globalThis`.

```js
// Both work in Node.js and point to the same object
console.log(global === globalThis);              // true
console.log(global.Math.PI);                     // 3.141592653589793
console.log(globalThis.Math.PI);                 // 3.141592653589793
console.log(globalThis.setTimeout === setTimeout); // true
```

* * *

## Do Not Put Your Own Variables on `global`

Node.js will let you attach your own values to `global`. It will not throw an error. But it is a pattern that tends to create problems you only discover months later.

Here is a common beginner mistake. You have a username that needs to be accessible across multiple files, and attaching it to `global` seems like a clean shortcut:

```js
// app.js
global.username = "User";
console.log("App started");

// greet.js
function greet() {
  console.log("Hello, " + username); // no import, just works
}

greet(); // "Hello, User"
```

This works right up until you have ten files, three months of code, and a bug where the username is printing wrong. You open `greet.js` looking for where `username` comes from, and there is nothing. No import. No declaration. You now have to trace through every file in the project to find where it was set.

Global variables have no trail. They appear from nowhere and make debugging slow and painful, especially when someone new joins the project.

The fix is straightforward:

```js
// user.js
const username = "User";
module.exports = username;

// greet.js
const username = require("./user");

function greet() {
  console.log("Hello, " + username);
}

greet(); // "Hello, User"
```

Now anyone reading `greet.js` knows immediately where `username` comes from. No searching required. As the codebase grows, that clarity pays off every single time.

* * *

## Conclusion

JavaScript was built for the browser, and Node.js pulled it out of that environment entirely. With that move came the need for a global object of its own, and that is `global`. Every built-in you use in Node.js without importing, `console`, `setTimeout`, `process`, `Buffer`, lives there.

The `this` behavior at the top level of a file is a side effect of how Node.js wraps your code in a function before running it. Once you know that, the `{}` output makes sense.

`globalThis` came along in ES2020 to give developers one consistent name for the global object across every JavaScript environment. In Node.js specifically, `global` and `globalThis` point to the same place. Which one you use depends on whether your code is staying in Node.js or needs to travel.

Either way, now you know where `console.log` actually comes from.

* * *

## References

*   [Node.js: Global Objects](https://nodejs.org/api/globals.html)
    
*   [MDN: globalThis](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis)
    
*   [javascript.info: Global Object](https://javascript.info/global-object)
