DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 967,611 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Alessio Michelini
Alessio Michelini

Posted on • Updated on

How to use ES Modules with Node.js

As most of frontend devs have enjoyed to use ES Modules (or ECMAScript Modules) for a long time, on the backend side of things most of devs still use CommonJS, as it’s still the standard way to import modules.
Since version 8.9.0 you could start to use ES Modules by adding the β€”experimental-modules flag, but you should never use anything experimental in production.

But since Node version 13 you don’t really need to use that flag anymore and as long you use any version from 16 (but it's also supported from version 14.14.0 and 12.20.0), it’s now fully supported to use, you just need to do a few small things.

In this article we are going to show how to run a small express server using ES Modules.

Set the right type on your package.json

I created a small sample project in node with just express as the only dependency, just as a proof of concept, I created a folder and then initialised a new Node project with npm init -y.

Installed Express and nodemon with npm i express -S and npm i nodemon -D, and added a start script in the package.json file, ending up with something like this:

{
  "name": "node-esm",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "nodemon index.mjs"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "module",
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.14"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, if you look closely to the code above, you might have noticed something different, the type property and the index.mjs file (we’ll discuss later about this file extension).

Regarding the first property, this has two possible values: commonjs and module.
The first one is your default value, which just tell to Node to use CommonJS , if you use the module option instead is going to tell to Node to use ECMAScript Modules instead.

And this is the only change you need to do in your package.json configuration.

Use the .mjs extension

This is the new official extension that also tells to Node that you are going to use a new ES Module, (more info here).

So in our little project we are going to have our index.mjs file, and another file that we are going to export a function to run for an endpoint, again with extension .mjs.

Our project file tree will look like this:

.
|-- modules
|   `-- test.mjs
|-- index.mjs
|-- package-lock.json
`-- package.json
Enter fullscreen mode Exit fullscreen mode

Add some code to the .mjs files

Create a simple index.mjs file with just the very basic Express implementation:

// index.mjs
import express from 'express';

const app = express();

app.use('/', (req, res) => res.status(200).send('HEALTHY'));

const { SERVER_PORT: port = 5010 } = process.env;

app.listen({ port }, () => {
  console.log(`πŸš€ Server ready at http://0.0.0.0:${port}`);
});
Enter fullscreen mode Exit fullscreen mode

So our modules/test.mjs will contain the following code:

// modules/test.mjs
export const sayHello = (req, res) => res.json({hello: 'world'});
Enter fullscreen mode Exit fullscreen mode

Nothing crazy here, just a function that handles an HTTP request with Express, and just return some sample JSON.

But the nice thing to see here is the export keyword!

Now let’s import this file in our index.mjs

// index.mjs
import express from 'express';
import { sayHello } from './modules/test.mjs';
Enter fullscreen mode Exit fullscreen mode

And then use it later in the code:

app.get('/hello', sayHello);
Enter fullscreen mode Exit fullscreen mode

And our index.mjs will look like this now:

import express from 'express';
import { sayHello } from './modules/test.mjs';

const app = express();

app.get('/hello', sayHello);
app.use('/', (req, res) => res.status(200).send('HEALTHY'));

const { SERVER_PORT: port = 5010 } = process.env;

app.listen({ port }, () => {
  console.log(`πŸš€ Server ready at http://0.0.0.0:${port}`);
});

Enter fullscreen mode Exit fullscreen mode

Start our application with npm start and here we are, our little server running with ES Modules instead of CommonJS :-)

> node-esm@1.0.0 start
> nodemon index.mjs

[nodemon] 2.0.14
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node index.mjs`
πŸš€ Server ready at http://0.0.0.0:5010
Enter fullscreen mode Exit fullscreen mode

This is great to see finally coming in Node.js, to standardise even more the code between frontend and backend in JavaScript!

Top comments (3)

Collapse
 
jobechoi profile image
JC Choi

Says "Now let’s import this file in our index.js." Think maybe to change to index.mjs?

Collapse
 
darkmavis1980 profile image
Alessio Michelini Author

You are right, thanks for spotting the typo!

Collapse
 
geforcesong profile image
George Guo

if you specify type=module in package.json, you don't need mjs extension, just .js file is fine.

Visualizing Promises and Async/Await 🀯

async await

☝️ Check out this all-time classic DEV post