556

I've just started working on a small node project that will interface with a MongoDB. However, I cannot seem to get the relevant node modules to import correctly, even though I have installed them correctly via npm.

For example, the following code throws an error, telling me that "express has no default export":

import express from "express";

However, this code works:

const express = require("express");

So my question is, what is the difference in how the import and variable/require methods function? I'd like to fix whatever is plaguing my imports on the project, as it seems likely to cause additional problems down the road.

zypA13510
  • 1,092
  • 1
  • 10
  • 28
austinthemassive
  • 5,907
  • 6
  • 21
  • 25
  • 3
    Unless you include the typing definitions for express, the first form won't make sense - in which case you can use the second form, but the variable `express` will be of type `any`. You could include the definitions from here https://www.npmjs.com/package/@types/express – fs_ Oct 11 '17 at 00:12
  • 6
    Possible duplicate of [Using Node.js require vs. ES6 import/export](https://stackoverflow.com/questions/31354559/using-node-js-require-vs-es6-import-export) – Ryall Aug 16 '18 at 16:57
  • @Ryall this is different question. Notice `import x = require('x')` is not the same as `var x = require('x')`. – Tomasz Gawel Nov 24 '20 at 12:16

8 Answers8

646

This simple image will help to you understand the differences between require and import.

enter image description here

Apart from that,

You can't selectively load only the pieces you need with require but with import, you can selectively load only the pieces you need, which can save memory.

Loading is synchronous(step by step) for require on the other hand import can be asynchronous(without waiting for previous import) so it can perform a little better than require.

A l w a y s S u n n y
  • 36,497
  • 8
  • 60
  • 103
  • 49
    Biggest difference that affects code is that exports in CommonJS modules are "computed", whereas exports in an ESM module are static (pre-defined). JS can determine the exports in an ESM module after only parsing the code (not yet running it). In a commonJS module, the exports are only known when the module actually runs and you see what is assigned to `module.exports` when the module initialization code finishes running. This difference alone creates compatibility headaches in trying to make a single module work for both ESM and CommonJS. – jfriend00 Jun 05 '20 at 02:39
  • 4
    ESM modules are friendlier to bundlers, but are more restrictive to coders because you can't have computed exports in ESM modules. – jfriend00 Jun 05 '20 at 02:41
  • 3
    "ESM" = ECMAScript Modules. I mention this for readers whose primary programming might not be JavaScript such as me. Here is a quick overview of module declaration in JavaScript https://dev.to/iggredible/what-the-heck-are-cjs-amd-umd-and-esm-ikm – camelCase Sep 26 '22 at 15:59
  • 2
    >`You can't selectively load only the pieces you need with require`: At least with Node.js you **can** selectively load only the pieces you need with `require`. For [example](https://nodejs.org/api/buffer.html#buffer): `const { Buffer } = require('node:buffer');`. – Nagev Nov 08 '22 at 16:49
160

The major difference between require and import, is that require will automatically scan node_modules to find modules, but import, which comes from ES6, won't.

Most people use babel to compile import and export, which makes import act the same as require.

The future version of Node.js might support import itself (actually, the experimental version already does), and judging by Node.js' notes, import won't support node_modules, it base on ES6, and must specify the path of the module.

So I would suggest you not use import with babel, but this feature is not yet confirmed, it might support node_modules in the future, who would know?


For reference, below is an example of how babel can convert ES6's import syntax to CommonJS's require syntax.

Say the fileapp_es6.js contains this import:

import format from 'date-fns/format';

This is a directive to import the format function from the node package date-fns.

The related package.json file could contain something like this:

"scripts": {
    "start": "node app.js",
    "build-server-file": "babel app_es6.js --out-file app.js",
    "webpack": "webpack"
}

The related .babelrc file could be something like this:

{
    "presets": [
        [
            "env",
            {
                "targets":
                {
                    "node": "current"
                }
            }
        ]
    ]
}

This build-server-file script defined in the package.json file is a directive for babel to parse the app_es6.js file and output the file app.js.

After running the build-server-file script, if you open app.js and look for the date-fns import, you will see it has been converted into this:

var _format = require("date-fns/format");

var _format2 = _interopRequireDefault(_format);

Most of that file is gobbledygook to most humans, however computers understand it.


Also for reference, as an example of how a module can be created and imported into your project, if you install date-fns and then open node_modules/date-fns/get_year/index.js you can see it contains:

var parse = require('../parse/index.js')

function getYear (dirtyDate) {
  var date = parse(dirtyDate)
  var year = date.getFullYear()
  return year
}

module.exports = getYear

Using the babel process above, your app_es6.js file could then contain:

import getYear from 'date-fns/get_year';

// Which year is 2 July 2014?
var result = getYear(new Date(2014, 6, 2))
//=> 2014

And babel would convert the imports to:

var _get_year = require("date-fns/get_year");

var _get_year2 = _interopRequireDefault(_get_year);

And handle all references to the function accordingly.

user1063287
  • 10,265
  • 25
  • 122
  • 218
A-yon Lee
  • 2,074
  • 2
  • 9
  • 18
  • 2
    aaaaahhhhhh. Babel hasn't been installed on this particular project, which makes everything make sense. I thought that ES6 imports/exports were functional already, but now I understand that Babel is just changing everything to `require` anyway – austinthemassive Oct 12 '17 at 17:21
  • stick to require for now. You can always change it in the future without any problem – John Apr 20 '18 at 17:15
  • 6
    `import won't support node_modules` What did you mean by that? – PrivateOmega Apr 11 '19 at 09:24
  • 5
    `import` and `require` both scan `node_modules` for the package specified by the statement. `require` loads anything assigned to `module.exports` in the package to the variable it's assigned to, or global scope if no left hand is declared. However, `import` will only load an es6 default export by name, unless all are assigned to an alias: `import * as X from 'pkg'`. You can import es6 packages with no default using *object destructuring* too: `import { X } from 'pkg'`. It'll work the same as `require` if you import the entire package, including all exports, to global scope `import 'package'`. – Rik Dec 04 '20 at 00:55
  • In recent `node`s, the `build-server-file` babel cmd in your `package.json` is not needed as seems. – Timo Dec 22 '22 at 16:30
62

Let me give an example for Including express module with require & import

-require

var express = require('express');

-import

import * as  express from 'express';

So after using any of the above statement we will have a variable called as 'express' with us. Now we can define 'app' variable as,

var app = express(); 

So we use 'require' with 'CommonJS' and 'import' with 'ES6'.

For more info on 'require' & 'import', read through below links.

require - Requiring modules in Node.js: Everything you need to know

import - An Update on ES6 Modules in Node.js

saikiran_hegde
  • 746
  • 7
  • 11
  • 7
    This is definitely the right answer. The poster had an issue with using the es6 `import` statement, and was confused by the **express has no default export** error. This answer provides the solution. Modules with multiple (and even single) exports which do not define a `default export` will need to have all exports assigned to a named variable, as the answer explains: `import * as whatever from 'package';` – Rik Dec 04 '20 at 00:16
  • Agreed, this should be the top answer. As an amendment to previous comment, you can check the code of the package that you are depending on in `node_modules` (the entrypoint will be listed under its `package.json` `main` key). Something like `module.export = whatever` means you likely have to import it as `import * as whatever from 'package';`. – zr0gravity7 Jan 07 '22 at 04:35
34

I will make it simple,

  • Import and Export are ES6 features(Next gen JS).
  • Require is old school method of importing code from other files

Major difference is in require, entire JS file is called or included. Even if you don't need some part of it.

var myObject = require('./otherFile.js'); //This JS file will be included fully.

Whereas in import you can extract only objects/functions/variables which are required.

import { getDate }from './utils.js'; 
//Here I am only pulling getDate method from the file instead of importing full file

Another major difference is you can use require anywhere in the program where as import should always be at the top of file

Edit: In Latest node versions you can use destructuring. It will look like this

const { getDate } = require('./date.js');
Jeb50
  • 6,272
  • 6
  • 49
  • 87
pranav shinde
  • 1,260
  • 13
  • 11
  • 7
    You can use object destructuring with `require`, e.g. `const { getDate } = require('./utils.js');` – d512 May 11 '21 at 04:44
  • 1
    Yes in latest node versions we can use, but in earlier versions it wasn't. – pranav shinde May 11 '21 at 05:49
  • 1
    Since version 6 (April 2016) destructured imports have been supported in Node. – Developer Dave Jun 28 '21 at 18:34
  • 2
    Your overall explanation is too simple and isn't accurate. Even the statement about using `require` anywhere in the program while `import` only at the top of the file is disguising important details. When you use `require` scoped to a function (or block scope somewhere in the application code) rather than scoped to the module/file this has an equivalent with ES modules (aka `import` syntax). It's an async operation though and this "dynamic importing" needs a `.then()` or an `await` keyword to be used. – Developer Dave Jun 28 '21 at 18:41
  • `require` does not "call" or "include" a file, it loads and executes a module. And of course it evaluates the whole code of the module, not just some part - exactly like `import` does! – Bergi Mar 02 '22 at 09:14
  • (-1) , and this is why: `(Next gen JS)` is not an answer. Second , if you do this `import { getDate }from './utils.js';` , you can also do this `const { getDate } = require('./utils.js');` , so it's would be better to explain the difference between those two , and not just jump and say `Next gen JS`. – JAN Jul 21 '22 at 07:46
21

new ES6:

'import' should be used with 'export' key words to share variables/arrays/objects between js files:

export default myObject;

//....in another file

import myObject from './otherFile.js';

old school:

'require' should be used with 'module.exports'

 module.exports = myObject;

//....in another file

var myObject = require('./otherFile.js');
Or Yaacov
  • 3,597
  • 5
  • 25
  • 49
LaZza
  • 360
  • 3
  • 7
10

There's a big difference between this:

import express from "express";

and this:

import * as express from "express";

the correct translation from CommonJS to ES6 of

const express = require("express");

is the second import.

Basically, that's because in the first import you are looking for an export in module express named express. The second one you are importing the whole express module with name express.

Vinicius
  • 432
  • 4
  • 8
2

These tools belong to different generations.

require exists only in CommonJS (the way Node.js created to import and export modules within an application), and import is ES6, ie, a new tool that both browser JavaScript and server JavaScript (Node.js ) can use.

In addition to this historical difference, there are differences in usage, where import is more flexible, modern and powerful than require.

It is important however to take into account that some browsers still do not support ES6, so it may be necessary to compile before using it.

require uses module.exports, which is the "old" (but still valid) syntax for exporting a module, which can be anything we want, an object, a string, etc.

import uses both, ie, you can use module.exports and export, and it allows you to export various pieces of code more or less like module.export did. One of the advantages of import is that it can only import parts of what was exported:

Examples:

File that exports:

// A.js file

// CommonJS syntax
module.exports = {
     foo: function(){ return 'bar';},
     baz: 123
}

// ES6 syntax
export function foo(){ return 'bar';}
export const baz = 123;

// or

function foo(){ return 'bar';}
const baz = 123;

export default {foo, baz};

File that imports:

// B.js file

// CommonJS syntax
const A = require('./A.js');
const foo = A.foo;
const baz = A.baz;

// ES6 syntax
import * as A from './A.js';
const foo = A.foo;
const baz = A.baz;

// or only
import {foo, baz} from './A.js';

When you use export default (ES6 syntax) it implies that you only export one thing per file. If it's an object, import can only import pieces. But if it's a function, for example, then you can just use import foo from './A.js'; without needing {} or * as foo.

Source: https://pt.stackoverflow.com/a/213938/317251

Pedro Siqueira
  • 386
  • 3
  • 8
1

import coming from ES6 is an update to the old CommonJs module where require came from. Down the line, I will differential the syntax difference but for now, let's understand why they updated this.

require is the function that is executed on runtime, which means it behaves like the other JavaScript functions if you define it in the middle of the script the above part of the script won't recognise it or if you put it inside the if statement it will only execute if the if expression will be true, or if you put it inside another function it will only execute when the function gets executed, etc.

On the other hand, import executes on a static level and it has some rules that it should always be on a root level and should not be inside any conditional statements or functions. Due to JavaScript static analysis for imports, it will throw compile time errors if you do so.

These were the advantages due to that the team changed the way of importing packages to ES6.

Then Why node is still using the CommonJs module when ES6 is better?

There is a huge code base that uses the CommonJs module in the node that is very difficult to convert to ES6 due to its support for years. But there are many tools that allow us to write ES6 code in node but down the line, these tools transpile it to CommonJs.

Syntax Differences:

Import totally depends on the way things are exported from the package.

If the default way of export is used while exporting a function or variable. like module.export = functionName in CommondJs or export default functionName in ES6 then imports will be like this.

Import in CommonJs vs ES6

const functionName = require("package/exampleFile"); // CommonJs

import functionName from "package/expampleFile.js"; // ES6.
// here you can see that we need to add .js at the end of the file

If multiple functions are exported like module.exports = {functionName1, functionName2} in CommonJs or export functionName1 export functionName2 in ES6 then the import will be like this.

const {functionName1, functionName2} = require("package/exampleFile"); // CommonJs

import {functionName1, functionName2} from "package/expampleFile.js"; // ES6.
Ali Murtaza
  • 414
  • 4
  • 9