217

I asked here: Does Node.js require inheritance?

And I was told that I can set variables to the global scope by leaving out the variable.

This does not work for me.

That is, the following does not make the _ available on required files.

_ = require('underscore');

I can set with Express.js's app.set and have it available elsewhere though.

Is that how this is supposed to work?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Harry
  • 52,711
  • 71
  • 177
  • 261

7 Answers7

242

You can use global like so:

global._ = require('underscore')
Danny
  • 669
  • 9
  • 20
masylum
  • 22,091
  • 3
  • 20
  • 20
  • 28
    Could you provide a little bit more information please? Is this part of javascript or part of node? Is it a good pattern to follow? As in should I do this or should I use express set? Thanks – Harry Mar 28 '11 at 03:34
  • 4
    The previous comment is incorrect. In the browser, `window` is the global object. `document` is a property of `window`. – G-Wiz Jul 13 '12 at 06:50
  • 78
    This is NOT a good pattern to follow. Don't do this. The convention of using 'require' to decouple modules is well thought out. You shouldn't violate it without a darn good reason. See my response below. – Dave Dopson Jul 30 '12 at 16:42
  • Globals are generally to be avoided, but if you really want to use them. The 3 statements below are all equivalent and will assign a var to the global scope: GLOBAL._ = require('underscore'); global._ = require('underscore'); _ = require('underscore'); – metaColin Aug 05 '15 at 18:23
  • When you're project starts getting a little bigger this will become a nightmare to maintain. Please take a look at my approach. – Oliver Dixon Feb 29 '16 at 17:54
  • `GLOBAL` is deprecated; use `global` instead. – Michał Miszczyszyn Aug 17 '16 at 15:52
  • Yeah 'global' is like the global 'window' object in the browser – Ratnesh Chandna Jul 25 '17 at 19:46
221

In Node.js, you can set global variables via the "global" or "GLOBAL" object:

GLOBAL._ = require('underscore'); // But you "shouldn't" do this! (see note below)

or more usefully...

GLOBAL.window = GLOBAL;  // Like in the browser

From the Node.js source, you can see that these are aliased to each other:

node-v0.6.6/src/node.js:
28:     global = this;
128:    global.GLOBAL = global;

In the code above, "this" is the global context. With the CommonJS module system (which Node.js uses), the "this" object inside of a module (i.e., "your code") is not the global context. For proof of this, see below where I spew the "this" object and then the giant "GLOBAL" object.

console.log("\nTHIS:");
console.log(this);
console.log("\nGLOBAL:");
console.log(global);

/* Outputs ...

THIS:
{}

GLOBAL:
{ ArrayBuffer: [Function: ArrayBuffer],
  Int8Array: { [Function] BYTES_PER_ELEMENT: 1 },
  Uint8Array: { [Function] BYTES_PER_ELEMENT: 1 },
  Int16Array: { [Function] BYTES_PER_ELEMENT: 2 },
  Uint16Array: { [Function] BYTES_PER_ELEMENT: 2 },
  Int32Array: { [Function] BYTES_PER_ELEMENT: 4 },
  Uint32Array: { [Function] BYTES_PER_ELEMENT: 4 },
  Float32Array: { [Function] BYTES_PER_ELEMENT: 4 },
  Float64Array: { [Function] BYTES_PER_ELEMENT: 8 },
  DataView: [Function: DataView],
  global: [Circular],
  process:
   { EventEmitter: [Function: EventEmitter],
     title: 'node',
     assert: [Function],
     version: 'v0.6.5',
     _tickCallback: [Function],
     moduleLoadList:
      [ 'Binding evals',
        'Binding natives',
        'NativeModule events',
        'NativeModule buffer',
        'Binding buffer',
        'NativeModule assert',
        'NativeModule util',
        'NativeModule path',
        'NativeModule module',
        'NativeModule fs',
        'Binding fs',
        'Binding constants',
        'NativeModule stream',
        'NativeModule console',
        'Binding tty_wrap',
        'NativeModule tty',
        'NativeModule net',
        'NativeModule timers',
        'Binding timer_wrap',
        'NativeModule _linklist' ],
     versions:
      { node: '0.6.5',
        v8: '3.6.6.11',
        ares: '1.7.5-DEV',
        uv: '0.6',
        openssl: '0.9.8n' },
     nextTick: [Function],
     stdout: [Getter],
     arch: 'x64',
     stderr: [Getter],
     platform: 'darwin',
     argv: [ 'node', '/workspace/zd/zgap/darwin-js/index.js' ],
     stdin: [Getter],
     env:
      { TERM_PROGRAM: 'iTerm.app',
        'COM_GOOGLE_CHROME_FRAMEWORK_SERVICE_PROCESS/USERS/DDOPSON/LIBRARY/APPLICATION_SUPPORT/GOOGLE/CHROME_SOCKET': '/tmp/launch-nNl1vo/ServiceProcessSocket',
        TERM: 'xterm',
        SHELL: '/bin/bash',
        TMPDIR: '/var/folders/2h/2hQmtmXlFT4yVGtr5DBpdl9LAiQ/-Tmp-/',
        Apple_PubSub_Socket_Render: '/tmp/launch-9Ga0PT/Render',
        USER: 'ddopson',
        COMMAND_MODE: 'unix2003',
        SSH_AUTH_SOCK: '/tmp/launch-sD905b/Listeners',
        __CF_USER_TEXT_ENCODING: '0x12D732E7:0:0',
        PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:~/bin:/usr/X11/bin',
        PWD: '/workspace/zd/zgap/darwin-js',
        LANG: 'en_US.UTF-8',
        ITERM_PROFILE: 'Default',
        SHLVL: '1',
        COLORFGBG: '7;0',
        HOME: '/Users/ddopson',
        ITERM_SESSION_ID: 'w0t0p0',
        LOGNAME: 'ddopson',
        DISPLAY: '/tmp/launch-l9RQXI/org.x:0',
        OLDPWD: '/workspace/zd/zgap/darwin-js/external',
        _: './index.js' },
     openStdin: [Function],
     exit: [Function],
     pid: 10321,
     features:
      { debug: false,
        uv: true,
        ipv6: true,
        tls_npn: false,
        tls_sni: true,
        tls: true },
     kill: [Function],
     execPath: '/usr/local/bin/node',
     addListener: [Function],
     _needTickCallback: [Function],
     on: [Function],
     removeListener: [Function],
     reallyExit: [Function],
     chdir: [Function],
     debug: [Function],
     error: [Function],
     cwd: [Function],
     watchFile: [Function],
     umask: [Function],
     getuid: [Function],
     unwatchFile: [Function],
     mixin: [Function],
     setuid: [Function],
     setgid: [Function],
     createChildProcess: [Function],
     getgid: [Function],
     inherits: [Function],
     _kill: [Function],
     _byteLength: [Function],
     mainModule:
      { id: '.',
        exports: {},
        parent: null,
        filename: '/workspace/zd/zgap/darwin-js/index.js',
        loaded: false,
        exited: false,
        children: [],
        paths: [Object] },
     _debugProcess: [Function],
     dlopen: [Function],
     uptime: [Function],
     memoryUsage: [Function],
     uvCounters: [Function],
     binding: [Function] },
  GLOBAL: [Circular],
  root: [Circular],
  Buffer:
   { [Function: Buffer]
     poolSize: 8192,
     isBuffer: [Function: isBuffer],
     byteLength: [Function],
     _charsWritten: 8 },
  setTimeout: [Function],
  setInterval: [Function],
  clearTimeout: [Function],
  clearInterval: [Function],
  console: [Getter],
  window: [Circular],
  navigator: {} }
*/

** Note: regarding setting "GLOBAL._", in general you should just do var _ = require('underscore');. Yes, you do that in every single file that uses Underscore.js, just like how in Java you do import com.foo.bar;. This makes it easier to figure out what your code is doing because the linkages between files are 'explicit'. It is mildly annoying, but a good thing. .... That's the preaching.

There is an exception to every rule. I have had precisely exactly one instance where I needed to set "GLOBAL._". I was creating a system for defining "configuration" files which were basically JSON, but were "written in JavaScript" to allow a bit more flexibility. Such configuration files had no 'require' statements, but I wanted them to have access to Underscore.js (the entire system was predicated on Underscore.js and Underscore.js templates), so before evaluating the "configuration", I would set "GLOBAL._". So yeah, for every rule, there's an exception somewhere. But you had better have a darn good reason and not just "I get tired of typing 'require', so I want to break with the convention".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dave Dopson
  • 41,600
  • 19
  • 95
  • 85
  • 7
    What are the downfalls of using GLOBAL? Why do I need a darn good reason? The bottom line is that my app works, right? – trusktr Aug 14 '12 at 08:22
  • 26
    ultimately, yes, if you ship, that's all that counts. However, certain practices are known as "best practices" and following them typically increases your odds of shipping and / or being able to maintain what you have built. The importance of following "good practice" increases with the size of the project and it's longevity. I've built all kinds of nasty hacks into short-lived projects that were write-once, read-never (and "single-developer"). In a bigger project, that sort of corner cutting ends up costing you project momentum. – Dave Dopson Aug 14 '12 at 18:00
  • 48
    Specifically, with GLOBAL, the issue is one of readability. If your program promiscuously uses global variables, it means that in order to understand the code, I must understand the dynamic runtime state of the entire app. This is why programmers are leery of globals. I'm sure there's dozens of ways to use them effectively, but we've mostly just seen them abused by junior programmers to the ill of the product. – Dave Dopson Aug 14 '12 at 18:05
  • 2
    Why can't you just put your configs in a regular `.js` file and call `require` before exporting the configs? – Azat Jul 25 '13 at 00:15
  • 1
    That's also a good question. Can't you just `var config = require('config.js');` and export the "written in JS" object? – trusktr Oct 11 '13 at 21:18
  • @Dave Dopson : I support the idea of putting config values into config.js and use `require('config.js')` ! It'll make searching all configs easier. – Dio Phung Feb 16 '14 at 05:38
  • @DaveDopson What about a scenario where you're separating your web app logic into separate .js files, and within those files, you need to reference centralized variables/functions/modules? You'd use global in this scenario, right? – Mason G. Zhwiti May 04 '14 at 03:14
  • @MasonG.Zhwiti: Nope, you have an abstraction which proxies the desired exports from the individual modules of some component and exposes them all through one module. With that way, a component which each consists of a dozen or more files can be used by require'ing a single file, and without polluting the global namespace. – Mark K Cowan Jun 10 '14 at 06:15
  • @MasonG.Zhwiti: In my current project, I have a `config` unit which used to read a config from JSON, but now does it from MySQL. This design change required changing only one file, the `config.js`. I also have some utility functions (things which underscore doesn't quite do the way I wanted), in a `util.js` – Mark K Cowan Jun 10 '14 at 06:16
  • About this specific use-case you mention that was the *"precisely exactly ONE instance"* where you needed `GLOBAL`, if it was generated code, couldn't you anyway have used `var _ = require('_')` at the top? I'm not saying there's a way around every case where you'd need `GLOBAL`, but this case could maybe have had the workaround (even if for the sake of whoever was reading the generated template code or whatever). – Camilo Martin Feb 02 '15 at 02:47
  • The case I used it was one where I had to define a db connection and do about 5 lines of setup. I get this in theory but that was 5 lines of code in essentially every JS lib. What is the real disadvantage to doing this? Is it just accidentally overriding core JS stuff? – Jackie Nov 19 '15 at 14:17
  • 4
    @Jackie - https://en.wikipedia.org/wiki/Singleton_pattern. if what you are doing maps to the Singleton pattern, then it might make sense. DB connections can be singletons when: 1) setup is expensive, 2) you only want the connection to be set up once, 3) the connection object is long-lived and won`t enter a failed state in the event of network hiccups, 4) the connection object is thread-safe / able to be shared by many different callers. – Dave Dopson Nov 20 '15 at 19:40
  • You're going to pollute name space with this and it WILL become a maintenance nightmare, I've seen it many times. Look at my approach. – Oliver Dixon Mar 25 '16 at 10:13
  • Is it only me to think "i get tired of typing 'require' so I want to break with convention" is damn good reason? – Adam Pietrasiak May 17 '16 at 09:42
  • This looks horrible. – Oliver Dixon May 29 '16 at 09:18
  • 1
    I don't know when but `GLOBAL` has apparently been deprecated in favor of `global`. I just got this warning in node 7.3.0 `DeprecationWarning: 'GLOBAL' is deprecated, use 'global'` – silverlight513 Feb 07 '17 at 11:08
  • For node modules this is quite okay, but what about all the files containing the classes of your own application? To require them you need to wire them to their paths, which becomes a nightmare. Not only to figure out the current releative path but also when refactoring and hence paths do change. – Artimus Nov 12 '17 at 13:14
  • mention that `GLOBAL` variable is deprecated and you have to use `global` – Ashkan Apr 18 '19 at 10:19
81

The other solutions that use the GLOBAL keyword are a nightmare to maintain/readability (+namespace pollution and bugs) when the project gets bigger. I've seen this mistake many times and had the hassle of fixing it.

Use a JavaScript file and then use module exports.

Example:

File globals.js

var Globals = {
    'domain':'www.MrGlobal.com';
}

module.exports = Globals;

Then if you want to use these, use require.

var globals = require('globals'); // << globals.js path
globals.domain // << Domain.
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Oliver Dixon
  • 7,012
  • 5
  • 61
  • 95
  • 13
    I surely don't love Unicorns but like your approach. Thanks. – Jonatas Walker Nov 30 '15 at 19:06
  • 1
    What about changing `globals.domain` though? – Fizzix May 28 '16 at 22:12
  • @Fizzix my suggestion here would be to use an observer pattern if you really need to change globals; in theory you should not be changing globals. – Oliver Dixon May 29 '16 at 09:06
  • 2
    @iLoveUnicorns thanks for replying. I'll look into alternatives such as 'express-session' since I mainly need it for storing the logged in user data. – Fizzix May 29 '16 at 09:53
  • 11
    While this in my opinion is a better approach, it does not create globals and does not answer the question asked. It's an alternative approach and I'd always encourage those, however the sheer bullish cocky-ness of statements like "This is the only correct answer on this thread" simply don't belong here. http://stackoverflow.com/help/be-nice – Vala Aug 08 '16 at 15:52
  • @Thor84no I changed it for you. – Oliver Dixon Nov 19 '16 at 08:57
  • 3
    This may be a better approach, but if you’re trying to run externally-authored scripts which rely on something being in the global namespace, this doesn’t help you. IOW, this doesn’t answer the question. – binki Dec 18 '16 at 02:44
  • "global" itself is just a module, pre-required for you on every file – tu4n Jul 01 '17 at 08:51
  • @OliverDixon - similar to @Fizzix, I am in a situation where I need to be able to access *and update* global variables from multiple modules, can u pls elaborate on how `observer pattern` would be implemented in a node/express environment? i have [a question with more context here](https://stackoverflow.com/questions/70185112/how-to-define-all-socket-io-io-onconnection-logic-outside-of-app-js-in-a-sep) – user1063287 Dec 02 '21 at 06:09
  • @user1063287 you can use ```export let``` then a setter function inside the file. – Oliver Dixon Dec 03 '21 at 08:25
13

Use a global namespace like global.MYAPI = {}:

global.MYAPI._ = require('underscore')

All other posters talk about the bad pattern involved. So leaving that discussion aside, the best way to have a variable defined globally (OP's question) is through namespaces.

Tip: Development Using Namespaces

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Igor Parra
  • 10,214
  • 10
  • 69
  • 101
  • 3
    That's what `require` is for! It's ok to use namespaces, but don't go all `global.foo = global.foo || {}` on all files, or something. Require the file that defines the namespace. Do it for the children. – Camilo Martin Feb 02 '15 at 02:42
  • @camilo-martin Hi, 1) By defining global.MYAPI._ you don't need define it in all files, That's the reason of being global. 2) This nothing has to be with the children. Even if all says that is bad pattern, It's depends of the programmer and the given situation how he use this capabiltiy of the language. – Igor Parra Feb 02 '15 at 15:08
  • 2
    Yes, but let's say you declare some of the functionality of a namespace in a separate file. Then you're requiring a file to use the object, which is backwards and goes against CommonJS and CommonSense, too. If you're going to require stuff, have the user code require the namespace and not be required by the namespace. Note I'm not saying anything *against* namespaces, just that there's conventions on who calls who for a reason. And in client-side you don't have what node has; see the link you mention is doing things in a certain way (through global) because it's about the browser and not node. – Camilo Martin Feb 02 '15 at 15:37
  • 1
    Sadly the URL you posted only works if you leave out the trailing slash ;) – Dirigible Mar 16 '19 at 16:13
11

You can just use the global object.

var X = ['a', 'b', 'c'];
global.x = X;

console.log(x);
//['a', 'b', 'c']
Joao Falcao
  • 274
  • 1
  • 3
  • 11
5

I agree that using the global/GLOBAL namespace for setting anything global is bad practice and don't use it at all in theory (in theory being the operative word). However (yes, the operative) I do use it for setting custom Error classes:

// Some global/configuration file that gets called in initialisation

global.MyError = [Function of MyError];

Yes, it is taboo here, but if your site/project uses custom errors throughout the place, you would basically need to define it everywhere, or at least somewhere to:

  1. Define the Error class in the first place
  2. In the script where you're throwing it
  3. In the script where you're catching it

Defining my custom errors in the global namespace saves me the hassle of require'ing my customer error library. Imaging throwing a custom error where that custom error is undefined.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DrunkenBeetle
  • 267
  • 4
  • 2
0

In case you are trying to access strings globally, I recommend using dotenv:

Install with:

npm i dotenv

Then create the file .env in the project's root directory and set all of the variables you want to be global, for example:

DB_HOST='localhost'
DB_DATABASE='my_database'
DB_USER='my_user'
DB_PASSWORD='my_password'

ADMIN_EMAIL='foo@bar.baz'
CITY='Some city'
# ... etc

You can even set these variables by the command line when starting the server like this:

NODE_ENV=dev PORT=5000 npm run start-dev

Also, if you use git, you likely want to add .env to your .gitignore to make sure you don't accidentally commit sensitive information.

Then just include the following at the beginning of your server.js file (or whatever the first file to be executed is)

require('dotenv').config()

To use these variables anywhere in your code, just use process.env.VARIABLE_NAME.

For example:

app.listen(process.env.PORT, () => {
    console.log(`Server is running on port ${process.env.PORT}.`)
})

Note: I understand this doesn't directly answer the question since it is about storing strings globally instead of Underscore.js, but I thought I would include it for completeness.

Mike
  • 23,542
  • 14
  • 76
  • 87