Your latest Node.js content, news and updates in one place.

Explain like I'm 5: Microservices in Node.js

Microservices are an architectural approach based on building an application as a collection of small services.

Let’s think of an application as a store. Applications are traditionally “monolithic” which means they are built as a single, autonomous unit --think of your favorite big-box store, selling everything from bananas to lawn furniture.


Everything is contained inside the unit. Let’s imagine that the person in this image - I’ll call him Jeff - is going inside the store to buy chewing gum and t-shirts. He can get a shopping cart to carry his purchases, look at products in different aisles, and pay at the checkstand before leaving--essentially, everything he needs is inside the store. These could also just as easily be components of an online Lego store application 👇.


All of this is run within a single process, and if our Lego store becomes very popular and we want to expand the business, we will have to add more Lego blocks in the same unit... and in the case of the online store, add more servers in order to scale it out.

So, every change (even minor changes) in our Lego store (physical or online) can be slow or tedious as it affects the entire system. In the case of Jeff’s store, a modification can require the removal or addition of multiple Lego blocks, affecting the entire structure. In the monolithic online store, a modification made to a small section of code might require building and deploying an entirely new version of software. So, scaling specific functions or components of the application, also means you have to scale the entire system.

Other problems with a monolithic approach in an online application are:

  • Inflexibility: it cannot be built using different technologies
  • Potentially unreliable: if even one feature of the system does not work, then the entire system does not work
  • Unscalable: applications cannot be scaled easily, since each time the application needs to be updated, the complete system has to be rebuilt
  • Not suitable for continuous development: many features of an application cannot be built and deployed at the same time
  • Slow development: As you can likely guess from the preceding points, development in monolithic applications takes a lot of time, since each feature has to be built individually, one after the other, rather than allowing multiple features to be worked on concurrently

This is where microservices come to the rescue!


Instead of containing everything in a single unit, the microservices-based application is broken down into smaller, lightweight pieces based on a logical construct. The application consists of independent small (micro-) services, and when we deploy or scale the app, individual services get distributed within a set of machines which we call “a cluster” in the service fabric world.

So in our Lego store example, perhaps one microservice contains a shopping cart, another one a product catalog, while another handles checkout, and so on. This approach allows developers to embrace compact and specialized tools that get each job done properly. Microservices are exactly that, scaled to enterprise level.

Microservices Diagram

Each service has its own unique and well-defined role, runs in its own process, and communicates via HTTP APIs or messaging. Each microservice can be deployed, upgraded, scaled, and restarted independently of all the sibling services in the application. They are typically managed by an automated system, making it possible to deploy frequent updates to live applications without affecting the end-users.

Following this pattern, Jeff’s store will be very different: now he won’t have one big store where he can find everything he needs, but there would have multiple stores and each store will be independent and have specific functions. The first store may contain only Lego castles, another one bridges, and another one, Lego rockets 🚀.

Screen Shot 2019-08-08 at 4.36.33 PM

All of the Lego stores will be part of a “Lego shopping mall” or “cluster,” and if I want to expand, scale, upgrade, or modify only the store selling rockets, the castle store (and the rest) won’t be affected.

In other words, developers identify the separate service “pieces” that are logically closely related and necessary parts of a project. Then, they choose from the options available that meet their particular needs, from open source to enterprise solutions, and knit everything together into a functional application.

Advantages of using microservices:

  • Allows us to build, operate and manage services independently, and we can easily scale them out based on the resources they need.
  • Microservices take a lot of infrastructure risk out of the project straight away. With the infrastructure made almost invisible, microservice teams can iterate quickly.
  • Each developer on a team can avoid getting tangled up in the underlying infrastructure, and focus on their piece of the project. Then, in production, if individual project modules don’t work exactly right together, it’s easy enough to isolate, disassemble and reconfigure them until they do. If shoppers aren’t big fans of the mall’s specialty ketchup store, a shoe store can be built in its place. It offers better resource utilization and cost optimization
  • Microservices have their own load balancer and execution environment to execute their functionalities, and at the same time, capture data in their own databases.
  • Finally, microservices offer language and platform freedom, so teams can choose the best language for the job at hand (even if that’s .NET for one team and Node.js for another team).

Drawbacks of microservices:

  • Microservices are not automatically the right solution for every project. When you are running multiple instances of the same service or worker, you don’t necessarily need microservices. A well-built monolithic system can scale just as well for some classes of problems.
  • One of the big problems with microservices is “orchestration”, which means how to integrate the services with a guide to drive the process, much like a conductor in an orchestra. Integrating microservices can be quite complex.
  • Another complex process is “discovery” which is how applications and (micro)services locate each other on a network.
  • Moving away from a monolithic app architecture means the loss of an opinionated workflow that previously glued all the pieces together.
  • There is a risk in getting a very fragmented system where developers need to spend a lot of time and effort on gluing together services and tools, and where there’s a lack of common patterns and platforms that makes it difficult to work across different projects.
  • Microservices can also require increased testing complexity and possibly increased memory/computing resources.
  • It’s possible to create un-scalable microservices. It all comes down to how well you apply the fundamental principles. It’s all too easy to jump into shopping for all the microservices you want to apply without first truly considering the problem set you’re applying them to

Creating Microservices with Node.js

In this example, we’re going to create a microservice using Node.js which connects to an external API.

The requirement for this service is to accept two Zip Codes of two Lego stores and return the distance between them in miles.

Initial Steps

  1. Have Node.js installed
  2. Run npm init in the root folder for the project. This will create a package.json file that will prompt some questions about the package, if you are not sure how to answer you can use the default.
  3. We are going to use two packages, Express and Require that can be installed like this:
$ npm install express request --save

Let’s look at the structure of the folders. There are two files and a folder created by the npm init command. These are package.json, package-lock.json, and node_modules. When we installed the express and request packages, their dependencies were downloaded and saved in node_modules.

Screen Shot 2019-08-01 at 3.54.03 PM

The primary file in our project is named server.js. And your package.json should look similar to this ☝️.

Then we create two folders, api for files that will support the API, and service for the logic to connect to a third-party API.

Screen Shot 2019-08-01 at 3.58.17 PM

Let’s build our service!

Creating a Server to Accept Requests

Create a file in the root folder for your project called server.js which will be our primary file. This file contains the code below.

const express = require('express')
const app = express();
const port = process.env.PORT || 3000;

const routes = require('./api/routes');
app.listen(port, function() {
   console.log('Server started on port: ' + port);

This file is creating our server and assigns routes to process all requests.

We first require express into the file, and use it to create a new app object const app = express(); then we specify the port, in this case, we use the environment variable called PORT, and if the variable isn’t defined, it will use the default port: 3000.

Then we bring the routes object from the routes.js file in the api folder. We’ll pass the app to the routes object, and that sets the routes for our application. Finally, we’ll tell the app to start listening on the port we defined and to display a message to the console when this process is complete.

Defining the routes

The next step is to define the routes for the microservices and then assign each to a target in the controller object (that will control the flow of data in the application). We’ll build the controller in the next step. We’ll have two endpoints. One endpoint called “about” that returns information about the application. And a “distance” endpoint that includes two path parameters, both Zip Codes of the Lego store. This endpoint returns the distance, in miles, between these two Zip Codes.

'use strict';

const controller = require('./controller');

module.exports = function(app) {

The ‘use strict’ directive at the top of the file is used by new versions of Javascript to enforce secure coding practices. The first thing we’ll do is to create a controller object which we’ll define in the next step. Module.exports allows us to declare functions inside a module, and have them available for use in another file. This file constitutes the routes module, which we imported into our primary server.js file and used it to define the routes for our express app. This function adds two routes to the app. The first route listens for GET requests on the /about endpoint. These requests are handled by the about function in the controller. The second route listens for GET requests on the /distance endpoint. The getDistance function in the controller handles these requests. Two parameters are also specified. These are labeled zipcode1 and zipcode2 respectively. Let’s build the controller to handle those requests.

Adding Controller Logic

Within the controller file, we’re going to create a controller object with two properties. Those properties are the functions to handle the requests we defined in the routes module.

'use strict';

var properties = require('../package.json')
var distance = require('../service/distance');

var controllers = {
   about: function(req, res) {
       var aboutInfo = {
           version: properties.version
   getDistance: function(req, res) {
           distance.find(req, res, function(err, dist) {
               if (err)

module.exports = controllers;

We have two distinct parts to our controller. We’ll go through the code for the about functionality first. At the top, we create an object called properties which references the package.json file which npm created when it bootstrapped the project. This file is in JavaScript Object Notation or JSON for short. This format affords us the ability to import and use the information it contains.

Within the controllers object, we define a property called about. This property is a function which accepts request and response objects. We’ll only use the response object for this function. Using the name and version information from the package.json file, we’ll build a new object and return it as the response.

For the getDistance functionality, we’ll start by bringing in the distance module. We’ll pass the request and response objects to the find function within this module. This function also includes a callback function. This function accepts an error object (err) and a distance object (dist). If there is an error in the response, we return that with our response; otherwise, we send back the results of the find function.

Making the External Call

We’re ready for the final piece of the puzzle. This file handles the call to a third-party API. We’ll use the distance API provided by (You need an API key to use this, and it is free if you register. You can also use the key from the example if you want to test your service, but this key frequently expires during the day).

I set my key as an environment variable on my system and named it ZIPCODEAPIKEY. The default key in the code is an expired test key from the ZipCodeAPI website.

var request = require('request');

const apiKey = process.env.ZIPCODE_API_KEY || "hkCt1nW1wF1rppaEmoor7T9G4ta7R5wFSu8l1dokNz8y53gGZHDneWWVosbEYirC";
const zipCodeURL = '';

var distance = {
   find: function(req, res, next) {
       request(zipCodeURL + apiKey 
               + '/distance.json/' + req.params.zipcode1 + '/' 
               + req.params.zipcode2 + '/mile',
       function (error, response, body) {
           if (!error && response.statusCode == 200) {
               response = JSON.parse(body);
           } else {
               console.log(response.statusCode + response.body);
               res.send({distance: -1});


module.exports = distance;

We’re using the request package to execute the external HTTP request, and we already discussed the api Key above. Ensure that you update it unless you want to start by testing the error conditions.

The find function accepts request, response and next objects as parameters. The request object accepts the URL of the service we’re calling and then defines a callback function to handle the response.

If there are no errors, and the status of the response is HTTP Status code 200, then the function parses out the body of the response into an object called response and returns it on the resp object. Since the ZipCodeAPI returns with a JSON response, we could forward this directly. Parsing it out allows us the option of doing more with the response if we choose to.

We log failures to the console, and then a result of -1 is sent on the response object. You may opt to create an error object to return as well.

Finally, we export the distance object, which allows the controller to instantiate it and call its functions as needed.


Assuming there aren’t any typos, your application should be ready to execute. Open a console window and run the following command:

npm start

Assuming it starts correctly, and the port you define is 3000, you can now open your browser and navigate to:

http://localhost:3000/about when you will see the name of the app and the version.

Screen Shot 2019-08-01 at 7.17.37 PM

Now if you add two parameters, the two zip codes, you will see something like this:


Screen Shot 2019-08-01 at 7.18.55 PM

And that’s it! Using microservices to know the distance between two zip codes!


In microservices, every single service is independently deployable, scalable and updatable, this is what makes microservices such an appealing architectural approach to the industry.

A microservice is loosely coupled and interacts with other microservices for well-defined interfaces using protocols like http, they remain consistent and available in the presence of failure, meaning even if the machine goes down that host a microservice, the functionality provided by the service should still be offered by the application.

While microservices are great, there is quite some work involved to build a scalable microservice application on a platform as you need to consider things like cluster management, service orchestration, inter-service communication and so on, and you also need to put a lot of effort into following DevOpsbest practices.

Not to mention that microservices can also require increased testing complexity and possibly increased memory/computing resources. Thus, despite the abundant potential benefits, those knowledgeable in the field caution that microservices are not automatically the right solution for every project.

  • Lego is a registered trademark


Read More
Understanding Streams in Node.js

Streams in Node.js have a reputation for being hard to work with, and even harder to understand.

In the words of Dominic Tarr: “Streams are Node’s best and most misunderstood idea.” Even Dan Abramov, creator of Redux and core team member of React.js is afraid of Node streams.


This article will help you understand streams and how to work with them. So, don’t be afraid. We can figure this out!

What are streams?

Streams are one of the fundamental concepts that power Node.js applications. They are data-handling method and are used to read or write input into output sequentially.

Streams are a way to handle reading/writing files, network communications, or any kind of end-to-end information exchange in an efficient way.

What makes streams unique, is that instead of a program reading a file into memory all at once like in the traditional way, streams read chunks of data piece by piece, processing its content without keeping it all in memory.

This makes streams really powerful when working with large amounts of data, for example, a file size can be larger than your free memory space, making it impossible to read the whole file into the memory in order to process it. That’s where streams come to the rescue!

Using streams to process smaller chunks of data, makes it possible to read larger files.

Let’s take a “streaming” services such as YouTube or Netflix for example: these services don’t make you download the video and audio feed all at once. Instead, your browser receives the video as a continuous flow of chunks, allowing the recipients to start watching and/or listening almost immediately.

However, streams are not only about working with media or big data. They also give us the power of ‘composability’ in our code. Designing with composability in mind means several components can be combined in a certain way to produce the same type of result. In Node.js it’s possible to compose powerful pieces of code by piping data to and from other smaller pieces of code, using streams.

Why streams

Streams basically provide two major advantages compared to other data handling methods:

  1. Memory efficiency: you don’t need to load large amounts of data in memory before you are able to process it
  2. Time efficiency: it takes significantly less time to start processing data as soon as you have it, rather than having to wait with processing until the entire payload has been transmitted

There are 4 types of streams in Node.js:

  1. Writable: streams to which we can write data. For example, fs.createWriteStream() lets us write data to a file using streams.
  2. Readable: streams from which data can be read. For example: fs.createReadStream() lets us read the contents of a file.
  3. Duplex: streams that are both Readable and Writable. For example, net.Socket
  4. Transform: streams that can modify or transform the data as it is written and read. For example, in the instance of file-compression, you can write compressed data and read decompressed data to and from a file.

If you have already worked with Node.js, you may have come across streams. For example, in a Node.js based HTTP server, request is a readable stream and response is a writable stream. You might have used the fs module, which lets you work with both readable and writable file streams. Whenever you’re using Express you are using streams to interact with the client, also, streams are being used in every database connection driver that you can work with, because of TCP sockets, TLS stack and other connections are all based on Node.js streams.

A practical example

How to create a readable stream

We first require the Readable stream, and we initialize it.

const Stream = require('stream')
const readableStream = new Stream.Readable()

Now that the stream is initialized, we can send data to it:


async iterator

It’s highly recommended to use async iterator when working with streams. According to Dr. Axel Rauschmayer, Asynchronous iteration is a protocol for retrieving the contents of a data container asynchronously (meaning the current “task” may be paused before retrieving an item). Also, it’s important to mention that the stream async iterator implementation use the ‘readable’ event inside.

You can use async iterator when reading from readable streams:

import * as fs from 'fs';

async function logChunks(readable) {
  for await (const chunk of readable) {

const readable = fs.createReadStream(
  'tmp/test.txt', {encoding: 'utf8'});

// Output:
// 'This is a test!\n'

It’s also possible to collect the contents of a readable stream in a string:

import {Readable} from 'stream';

async function readableToString2(readable) {
  let result = '';
  for await (const chunk of readable) {
    result += chunk;
  return result;

const readable = Readable.from('Good morning!', {encoding: 'utf8'});
assert.equal(await readableToString2(readable), 'Good morning!');

Note that, in this case, we had to use an async function because we wanted to return a Promise.

It’s important to keep in mind to not mix async functions with EventEmitter because currently, there is no way to catch a rejection when it is emitted within an event handler, causing hard to track bugs and memory leaks. The best current practice is to always wrap the content of an async function in a try/catch block and handle errors, but this is error prone. This pull request aims to solve this issue once it lands on Node core.

To learn more about Node.js streams via async iteration, check out this great article.

Readable.from(): Creating readable streams from iterables

stream.Readable.from(iterable, [options]) it’s a utility method for creating Readable Streams out of iterators, which holds the data contained in iterable. Iterable can be a synchronous iterable or an asynchronous iterable. The parameter options is optional and can, among other things, be used to specify a text encoding.

const { Readable } = require('stream');

async function * generate() {
  yield 'hello';
  yield 'streams';

const readable = Readable.from(generate());

readable.on('data', (chunk) => {

Two Reading Modes

According to Streams API, readable streams effectively operate in one of two modes: flowing and paused. A Readable stream can be in object mode or not, regardless of whether it is in flowing mode or paused mode.

  • In flowing mode, data is read from the underlying system automatically and provided to an application as quickly as possible using events via the EventEmitter interface.
  • In paused mode, the method must be called explicitly to read chunks of data from the stream.

In a flowing mode, to read data from a stream, it’s possible to listen to data event and attach a callback. When a chunk of data is available, the readable stream emits a data event and your callback executes. Take a look at the following snippet:

var fs = require("fs");
var data = '';

var readerStream = fs.createReadStream('file.txt'); //Create a readable stream

readerStream.setEncoding('UTF8'); // Set the encoding to be utf8. 

// Handle stream events --> data, end, and error
readerStream.on('data', function(chunk) {
   data += chunk;

readerStream.on('end',function() {

readerStream.on('error', function(err) {

console.log("Program Ended");

The function call fs.createReadStream() gives you a readable stream. Initially, the stream is in a static state. As soon as you listen to data event and attach a callback it starts flowing. After that, chunks of data are read and passed to your callback. The stream implementor decides how often a data event is emitted. For example, an HTTP request may emit a data event once every few KBs of data are read. When you are reading data from a file you may decide you emit a data event once a line is read.

When there is no more data to read (end is reached), the stream emits an end event. In the above snippet, we listen to this event to get notified when the end is reached.

Also, if there is an error, the stream will emit and notify the error.

In paused mode, you just need to call read() on the stream instance repeatedly until every chunk of data has been read, like in the following example:

var fs = require('fs');
var readableStream = fs.createReadStream('file.txt');
var data = '';
var chunk;

readableStream.on('readable', function() {
    while (( != null) {
        data += chunk;

readableStream.on('end', function() {

The read() function reads some data from the internal buffer and returns it. When there is nothing to read, it returns null. So, in the while loop, we check for null and terminate the loop. Note that the readable event is emitted when a chunk of data can be read from the stream.

All Readable streams begin in paused mode but can be switched to flowing mode in one of the following ways:

  • Adding a 'data' event handler.
  • Calling the stream.resume() method.
  • Calling the stream.pipe() method to send the data to a Writable.

The Readable can switch back to paused mode using one of the following:

  • If there are no pipe destinations, by calling the stream.pause() method.
  • If there are pipe destinations, by removing all pipe destinations. Multiple pipe destinations may be removed by calling the stream.unpipe() method.

The important concept to remember is that a Readable will not generate data until a mechanism for either consuming or ignoring that data is provided. If the consuming mechanism is disabled or taken away, the Readable will attempt to stop generating the data. Adding a readable event handler automatically make the stream to stop flowing, and the data to be consumed via If the 'readable' event handler is removed, then the stream will start flowing again if there is a 'data' event handler.

How to create a writable stream

To write data to a writable stream you need to call write() on the stream instance. Like in the following example:

var fs = require('fs');
var readableStream = fs.createReadStream('file1.txt');
var writableStream = fs.createWriteStream('file2.txt');


readableStream.on('data', function(chunk) {

The above code is straightforward. It simply reads chunks of data from an input stream and writes to the destination using write(). This function returns a boolean value indicating if the operation was successful. If true, then the write was successful and you can keep writing more data. If false is returned, it means something went wrong and you can’t write anything at the moment. The writable stream will let you know when you can start writing more data by emitting a drain event.

Calling the writable.end() method signals that no more data will be written to the Writable. If provided, the optional callback function is attached as a listener for the 'finish' event.

// Write 'hello, ' and then end with 'world!'.
const fs = require('fs');
const file = fs.createWriteStream('example.txt');
file.write('hello, ');
// Writing more now is not allowed!

Using a writable stream you can read data from a readable stream:

const Stream = require('stream')

const readableStream = new Stream.Readable()
const writableStream = new Stream.Writable()

writableStream._write = (chunk, encoding, next) => {




You can also use async iterators to write to a writable stream, which is recommended

import * as util from 'util';
import * as stream from 'stream';
import * as fs from 'fs';
import {once} from 'events';

const finished = util.promisify(stream.finished); // (A)

async function writeIterableToFile(iterable, filePath) {
  const writable = fs.createWriteStream(filePath, {encoding: 'utf8'});
  for await (const chunk of iterable) {
    if (!writable.write(chunk)) { // (B)
      // Handle backpressure
      await once(writable, 'drain');
  writable.end(); // (C)
  // Wait until done. Throws if there are errors.
  await finished(writable);

await writeIterableToFile(
  ['One', ' line of text.\n'], 'tmp/log.txt');
  fs.readFileSync('tmp/log.txt', {encoding: 'utf8'}),
  'One line of text.\n');

The default version of stream.finished() is callback-based but can be turned into a Promise-based version via util.promisify() (line A).

In this example, it is used the following two patterns:

Writing to a writable stream while handling backpressure (line B):

if (!writable.write(chunk)) {
  await once(writable, 'drain');

Closing a writable stream and waiting until writing is done (line C):

await finished(writable);


Piping is a mechanism where we provide the output of one stream as the input to another stream. It is normally used to get data from one stream and to pass the output of that stream to another stream. There is no limit on piping operations. In other words, piping is used to process streamed data in multiple steps.

In Node 10.x was introduced stream.pipeline(). This is a module method to pipe between streams forwarding errors and properly cleaning up and provide a callback when the pipeline is complete.

Here is an example of using pipeline:

const { pipeline } = require('stream');
const fs = require('fs');
const zlib = require('zlib');

// Use the pipeline API to easily pipe a series of streams
// together and get notified when the pipeline is fully done.
// A pipeline to gzip a potentially huge video file efficiently:

  (err) => {
    if (err) {
      console.error('Pipeline failed', err);
    } else {
      console.log('Pipeline succeeded');

pipeline should be used instead of pipe, as pipe is unsafe.

The Stream Module

The Node.js stream module provides the foundation upon which all streaming APIs are build.

The Stream module is a native module that shipped by default in Node.js. The Stream is an instance of the EventEmitter class which handles events asynchronously in Node. Because of this, streams are inherently event-based.

To access the stream module:

const stream = require('stream');

The stream module is useful for creating new types of stream instances. It is usually not necessary to use the stream module to consume streams.

Streams-powered Node APIs

Due to their advantages, many Node.js core modules provide native stream handling capabilities, most notably:

  • net.Socket is the main node api that is stream are based on, which underlies most of the following APIs
  • process.stdin returns a stream connected to stdin
  • process.stdout returns a stream connected to stdout
  • process.stderr returns a stream connected to stderr
  • fs.createReadStream() creates a readable stream to a file
  • fs.createWriteStream() creates a writable stream to a file
  • net.connect() initiates a stream-based connection
  • http.request() returns an instance of the http.ClientRequest class, which is a writable stream
  • zlib.createGzip() compress data using gzip (a compression algorithm) into a stream
  • zlib.createGunzip() decompress a gzip stream.
  • zlib.createDeflate() compress data using deflate (a compression algorithm) into a stream
  • zlib.createInflate() decompress a deflate stream

Streams Cheat Sheet:

cheat1 cheat2 cheat3 cheat3

See more: [Node.js streams cheatsheet](

Here are some important events related to writable streams:

  • error – Emitted to indicate that an error has occurred while writing/piping.
  • pipeline – When a readable stream is piped into a writable stream, this event is emitted by the writable stream.
  • unpipe – Emitted when you call unpipe on the readable stream and stop it from piping into the destination stream.


This was all about the basics of streams. Streams, pipes, and chaining are the core and most powerful features in Node.js. Streams can indeed help you write neat and performant code to perform I/O.

Also, there is a Node.js strategic initiative worth looking to, called BOB, aiming to improve Node.js streaming data interfaces, both within Node.js core internally, and hopefully also as future public APIs.


Special thanks to Matteo Colina and Jeremiah Senkpiel for your feedback!

Read More
Memory Leaks Demystified

Tracking down memory leaks in Node.js has been a recurring topic, people are always interested in learning more about due to the complexity and the range of causes.

Not all memory leaks are immediately obvious - quite the opposite; however once we identify a pattern, we must look for a correlation between memory usage, objects held in memory and response time. When examining objects, look into how many of them are collected, and whether any of them are usual, depending on the framework or technique used to serve the content (ex. Server Side Rendering). Hopefully, after you finish this article, you'll be able to understand, and look for a strategy to debug the memory consumption of a Node.js application.

Garbage Collection Theory in Node.js

JavaScript is a garbage collected language and Google’s V8 is a JavaScript engine, initially created for Google Chrome, that can be used as a standalone runtime in many instances. Two important operations of the Garbage Collector in Node.js are:

  1. identify live or dead objects and
  2. recycle/reuse the memory occupied by dead objects.

Something important to keep in mind: When the Garbage Collector runs, it pauses your application entirely until it finishes its work. As such you will need to minimize its work by taking care of your objects’ references.

All memory used by a Node.js process is being automatically allocated and de-allocated by the V8 JavaScript engine. Let’s see how this looks in practice.

If you think of memory as a graph, then imagine V8 keeping a graph of all variables in the program, starting from the ‘Root node’. This could be your window or the global object in a Node.js module, usually known as the dominator. Something important to keep in mind is you don’t control how this Root node is de-allocated.


Next, you’ll find an Object node, usually known as leaves (there are no child references). Finally, there are 4 types of data types in JavaScript: Boolean, String, Number, and Object.

V8 will walk through the graph and try to identify groups of data that can no longer be reached from the Root node. If it’s not reachable from the Root node, V8 assumes that the data is no longer used and releases the memory. Remember: to determine whether an object is live, it is necessary to check if is reachable through some chain of pointers from an object which is live by definition; everything else, such as an object being unreachable from a root node or not referenceable by a root node or another live object is considered garbage.

In a nutshell, the garbage collector has two main tasks;

  1. trace and
  2. count references between objects.

It can get tricky when you need to track remote references from another process, but in Node.js applications, we use a single process which makes our life a bit easier.

V8’s Memory Scheme

V8 uses a scheme similar to the Java Virtual Machine and divides the memory into segments. The thing that wraps the scheme concept is known as Resident Set, which refers to the portion of memory occupied by a process that is held in the RAM.

Inside the Resident Set you will find:

  • Code Segment: Where the actual code is being executed.
  • Stack: Contains local variables and all value types with pointers referencing objects on the heap or defining the control flow of the application.
  • Heap: A memory segment dedicated to storing reference types like objects, strings and closures.

Two more important things to keep in mind:

  • Shallow size of an object: the size of memory that is held by the object itself
  • Retained size of an object: the size of the memory that is freed up once the object is deleted along with its' dependent objects

Node.js has an object describing the memory usage of the Node.js process measured in bytes. Inside the object you’ll find:

  • rss: Refers to resident set size.
  • heapTotal and heapUsed: Refers to V8's memory usage.
  • external: refers to the memory usage of C++ objects bound to JavaScript objects managed by V8.

Finding the leak

Chrome DevTools is a great tool that can be used to diagnose memory leaks in Node.js applications via remote debugging. Other tools exist and they will give you the similar. This blog post relies on one of those different tools in order to give you a clear clear understanding of what is happening. However, you need to keep in mind that profiling is an intensive CPU task, which can impact your application negatively. Be aware!

The Node.js application we are going to profile is a simple HTTP API Server that has multiple endpoints, returning different information to whoever is consuming the service. You can clone the repository of the Node.js application used here.

const http = require('http')

const leak = []

function requestListener(req, res) {

  if (req.url === '/now') {
    let resp = JSON.stringify({ now: new Date() })
    res.writeHead(200, { 'Content-Type': 'application/json' })
  } else if (req.url === '/getSushi') {
    function importantMath() {
    let endTime = + (5 * 1000);
    while ( < endTime) {

    function theSushiTable() {
    return new Promise(resolve => {

    async function getSushi() {
    let sushi = await theSushiTable();
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
    res.write(`Enjoy! ${sushi}`);

  } else {
    res.end('Invalid request')

const server = http.createServer(requestListener)
server.listen(process.env.PORT || 3000)

Start the Node.js application:


We have been using a 3S (3 Snapshot) approach to diagnostics and identify possible memory issues. Interesting enough, we found this was an approach that has been used by Loreena Lee at the Gmail team for a long time to solve memory issues. A walkthrough for this approach:

  1. Open Chrome DevTools and visit chrome://inspect.
  2. Click on the inspect button from one of your applications in the Remote Target section located at the bottom.

Note: Make sure you have the Inspector attached to the Node.js application you want to profile. You can also connect to Chrome DevTools using ndb .

You are going to see a Debugger Connected message in the output of your console when the app is running.

  1. Go to Chrome DevTools > Memory
  2. Take a heap snapshot

In this case, we took the first snapshot without any load or processing being done by the service. This a tip for certain use-cases: it’s fine if we are completely sure the application doesn’t require any warm up before accepting request or do some processing. Sometimes it makes sense to do a warm-up action before taking the first heap snapshot as there are cases where you might be doing lazy initialization for global variables on the first invocation.

  1. Perform the action in your app that you think is causing leaks in memory.

In this case we are going to run npm run load-mem. This will start ab to simulate traffic/load in your Node.js application.

  1. Take a heap snapshot
  1. Again, perform the action in your app that you think is causing leaks in memory.
  2. Take a final heap snapshot
  1. Select the latest snapshot taken.
  2. At the top of the window, find the drop-down that says “All objects” and switch this to “Objects allocated between snapshots 1 and 2”. (You can also do the same for 2 and 3 if needed). This will substantially cut down on the number of objects that you see.

The Comparison view can help you identify those Objects too:


In the view you’ll see a list of leaked objects that are still hanging around, top level entries (a row per constructor), columns for distance of the object to the GC root, number of object instances, shallow size and retained size. You can select one to see what is being retained in its retaining tree. A good rule of thumb is to first ignore the items wrapped in parenthesis as those are built-in structures. The @ character is objects’ unique ID, allowing you to compare heap snapshots on per-object basis.

A typical memory leak might retain a reference to an object that’s expected to only last during one request cycle by accidentally storing a reference to it in a global object that cannot be garbage collected.

This example generates a random object with the date timestamp when the request was made to imitate an application object that might be returned from an API query and purposefully leak it by storing it in a global array. Looking at a couple of the retained Object’s you can see some examples of the data that has been leaked, which you can use to track down the leak in your application.

NSolid is great for this type of use-case, because it gives you a really good insight of how memory is increasing on every task or load-test you perform. You can also see in real time how every profiling action impacts CPU if you were curious.


In real world situations, memory leaks happen when you are not looking at the tool you use to monitor your application, something great about NSolid is the ability to set thresholds and limits for different metrics of your application. For example, you can set NSolid to take a heap snapshot if more than X amount of memory is being used or during X time memory hasn’t recovered from a high consumption spike. Sounds great, right?

Get started with low-impact memory leaks monitoring Create your NodeSource Account

Marking and Sweeping

V8’s garbage collector is mainly based on the Mark-Sweep collection algorithm which consists of tracing garbage collection that operates by marking reachable objects, then sweeping over memory and recycling objects that are unmarked (which must be unreachable), putting them on a free list. This is also known as a generational garbage collector where objects may move within the young generation, from the young to the old generation, and within the old generation.

Moving objects is expensive since the underlying memory of objects needs to be copied to new locations and the pointers to those objects are also subject to updating.

For mere mortals, this could be translated to:

V8 looks recursively for all objects’ reference paths to the Root node. For example: In JavaScript, the "window" object is an example of a global variable that can act as a Root. The window object is always present, so the garbage collector can consider it and all of its children to be always present (i.e. not garbage). If any reference has no path to the Root node. especially when it looks for unreferenced objects recursively, it will be marked as garbage and will be swept later to free that memory and return it to the OS.

However, modern garbage collectors improve on this algorithm in different ways, but the essence is the same: reachable pieces of memory are marked as such and the rest is considered garbage.

Remember, everything that can be reached from a Root is not considered garbage. Unwanted references are variables kept somewhere in the code that will not be used anymore and point to a piece of memory that could otherwise be freed, so to understand the most common leaks in JavaScript, we need to know the ways references are commonly forgotten.

The Orinoco Garbage Collector

Orinoco is the codename of the latest GC project to make use of the latest and greatest parallel, incremental and concurrent technique for garbage collection, featuring the ability to free the main thread. One of the significant metrics describing Orinoco’s performance is how often and how long the main thread pauses while the garbage collector performs its functions. For classic ‘stop-the-world’ collectors, these time-intervals impact the application’s user experience due to delays, poor-quality rendering, and an increase in response time.

V8 distributes the work of garbage collection between auxiliary streams in young memory (scavenging). Each stream receives a set of pointers, followed by moving all living objects into “to-space”.

When moving objects into ‘to-space’, threads need to synchronize through atomic read / write / compare and swap operations to avoid a situation where, for example, another thread found the same object, but followed a different path, and tries to move it.

Quote from V8 page:

Adding parallel, incremental and concurrent techniques to the existing GC was a multi-year effort, but has paid off, moving a lot of work to background tasks. It has drastically improved pause times, latency, and page load, making animation, scrolling, and user interaction much smoother. The parallel Scavenger has reduced the main thread young generation garbage collection total time by about 20%–50%, depending on the workload. Idle-time GC can reduce Gmail’s JavaScript heap memory by 45% when it is idle. Concurrent marking and sweeping has reduced pause times in heavy WebGL games by up to 50%.

The Mark-Evacuate collector consists of three phases: marking, copying, and updating pointers. To avoid sweeping pages in the young generation to maintain free lists, the young generation is still maintained using a semi-space that is always kept compact by copying live objects into “to-space” during garbage collection. It's advantage being parallel is that ‘exact liveness’ information is available. This information can be used to avoid copying by just moving and relinking pages that contain mostly live objects, which is also performed by the full Mark-Sweep-Compact collector. It works by marking live objects in the heap in the same fashion as the mark-sweep algorithm, meaning the heap will often be fragmented. V8 currently ships with the parallel Scavenger which reduces the main thread young generation garbage collection total time by about 20%–50% across a large set of benchmarks.

Everything related to pausing of the main thread, response time and page load has significantly improved, which allows animations, scrolling and user interaction on the page to be much smoother. The parallel collector made it possible to reduce the total duration of processing of young memory by 20–50%, depending on the load. However, the work is not over: Reducing pauses remains an important task to simplify the lives of web users, and we continue to look for the possibility of using more advanced techniques to achieve the goal.


Most developers don’t need to think about GC when developing JavaScript programs, but understanding some of the internals can help you think about memory usage and helpful programming patterns. For example, given the structure of the heap in V8, based on generations, low-living objects are actually quite cheap in terms of GC, since we pay mainly for the surviving objects. This kind of pattern is not only particular to JavaScript but also to many languages with garbage collection support.

Main Takeaways:

  • Do not use outdated or deprecated packages like node-memwatch, node-inspector or v8-profiler to inspect and learn about memory. Everything you need is already integrated in the Node.js binary (especially a node.js inspector and debugger). If you need more specialized tooling, you can use NSolid, Chrome DevTools and other well known software.
  • Consider where and when you trigger heap snapshots and CPU profiles. You will want to trigger both, mostly in testing, due to the intensity of CPU operations that are required to take a snapshot in production. Also, be sure of how many heap-dumps are fine to write out before shutting the process and causing a cold restart.
  • There’s no one tool for everything. Test, measure, decide and resolve depending on the application. Choose the best tool for your architecture and the one that delivers more useful data to figure out the issue.


Read More
An Absolute Beginner's Guide to Using npm

This article was first published in NodeSource blog on February 2017.

Using npm effectively is a cornerstone of modern web development, no matter if it's exclusively with Node.js, as a package manager or build tool for the front-end, or even as a piece of workflows in other languages and on other platforms.

Really understanding npm as a tool, understanding the core concepts, can be something that's difficult for a beginner - I spent many hours just trying to figure out small details that would seem minor or be taken for granted by others.

As such, I've written up a basic and detailed guide for understanding npm, for those who are entirely new to Node.js, npm, and the surrounding ecosystem.

An Absolute Beginner's Guide to package.json

As a general rule, any project that's using Node.js will need to have a package.json file. What is a package.json file?

At its simplest, a package.json file can be described as a manifest of your project that includes the packages and applications it depends on, information about its unique source control, and specific metadata like the project's name, description, and author.

Let's break down the core parts of a typical package.json file:

Specific Metadata: name, version, description, license, and keywords

Inside a package.json, you'll almost always find metadata specific to the project - no matter if it's a web application, Node.js module, or even just a plain JavaScirpt library. This metadata helps identify the project and acts as a baseline for users and contributors to get information about the project.

Here's an example of how these fields would look in a package.json file:

  "name": "metaverse", // The name of your project
  "version": "0.92.12", // The version of your project
  "description": "The Metaverse virtual reality. The final outcome of all virtual worlds, augmented reality, and the Internet.", // The description of your project
  "main": "index.js"
  "license": "MIT" // The license of your project

A package.json file is always structured in the JSON format, which allows it to be easily read as metadata and parsed by machines.

If needing to format a package.json file manually to get your project up and running seems a bit daunting, there's a handy command that will automatically generate a base package.json file for you - if you'd like to learn how to use it, take a peek at the npm init instructions below!

Understanding and Managing Your Project's Dependencies: dependencies and devDepenendcies in your package.json

The other majorly important aspect of a package.json is that it contains a collection of any given project's dependencies. These dependencies are the modules that the project relies on to function properly.

Having dependencies in your project's package.json allows the project to install the versions of the modules it depends on. By running an install command (see the instructions for npm install below) inside of a project, you can install all of the dependencies that are listed in the project's package.json - meaning they don't have to be (and almost never should be) bundled with the project itself.

Second, it allows the separation of dependencies that are needed for production and dependencies that are needed for development. In production, you're likely not going to need a tool to watch your CSS files for changes and refresh the app when they change. But in both production and development, you'll want to have the modules that enable what you're trying to accomplish with your project - things like your web framework, API tools, and code utilities.

What would a project's package.json look like with dependencies and devDependencies? Let's expand on the previous example of a package.json to include some.

  "name": "metaverse",
  "version": "0.92.12",
  "description": "The Metaverse virtual reality. The final outcome of all virtual worlds, augmented reality, and the Internet.",
  "main": "index.js"
  "license": "MIT",
  "devDependencies": {
    "mocha": "~3.1",
    "native-hello-world": "^1.0.0",
    "should": "~3.3",
    "sinon": "~1.9"
  "dependencies": {
    "fill-keys": "^1.0.2",
    "module-not-found-error": "^1.0.0",
    "resolve": "~1.1.7"

One key difference between the dependencies and the other common parts of a package.json is that they're both objects, with multiple key/value pairs. Every key in both dependencies and devDependencies is a name of a package, and every value is the version range that's acceptable to install (according to Semantic Versioning - to learn more about Semantic Versioning, also known as semver, check out our primer on semver).

Can't get enough npm? Download our complete guide: Read now: The Ultimate Guide to npm

The Essential npm Commands

When using npm, you're most likely going to be using the command line tool for the majority of your interactions. As such, here's a detailed rundown of the commands that you'll encounter and need to use most frequently.

Using npm init to Initialize a Project

The npm init command is a step-by-step tool to scaffold out your project. It will prompt you for input for a few aspects of the project in the following order:

  • The project's name,
  • The project's initial version,
  • The project's description,
  • The project's entry point (meaning the project's main file),
  • The project's test command (to trigger testing with something like Standard)
  • The project's git repository (where the project source can be found)
  • The project's keywords (basically, tags related to the project)
  • The project's license (this defaults to ISC - most open-source Node.js projects are MIT)

It's worth noting that if you're content with the suggestion that the npm init command provides next to the prompt, you can simply hit Return or Enter to accept the suggestion and move on to the next prompt.

Once you run through the npm init steps above, a package.json file will be generated and placed in the current directory. If you run it in a directory that's not exclusively for your project, don't worry! Generating a package.json doesn't really do anything, other than create a package.json file. You can either move the package.json file to a directory that's dedicated to your project, or you can create an entirely new one in such a directory.

How to use npm init:

npm init # This will trigger the initialization

Using npm init --yes to Instantly Initialize a Project

If you want to get on to building your project, and don't want to spend the (albeit brief) time answering the prompts that come from npm init, you can use the --yes flag on the npm init command to automatically populate all options with the default npm init values.

Note: You can configure what these default values are with the npm configuration - that's a more advanced topic, and outside the scope of this beginner's guide to npm.

That said, if you're interested in setting that up, you can learn how to set these defaults in the eleventh tip of our npm tricks article.


npm init --yes # This will trigger automatically populated initialization.

Install Modules with npm install

Installing modules from npm is one of the most basic things you should learn to do when getting started with npm. As you dive deeper, you'll begin to learn some variations on installing modules, but here's the very core of what you need to know to install a standalone module into the current directory:

npm install <module>

In the above command, you'd replace <module> with the name of the module you want to install. For example, if you want to install Express (the most used and most well known Node.js web framework), you could run the following command:

npm install express

The above command will install the express module into /node_modules in the current directory. Whenever you install a module from npm, it will be installed into the node_modules folder.

In addition to triggering an install of a single module, you can actually trigger the installation of all modules that are listed as dependencies and devDependencies in the package.json in the current directory. To do so, you'll simply need to run the command itself:

npm install

Once you run this, npm will begin the installation process of all of the current project's dependencies.

As an aside, one thing to note is that there's an alias for npm install that you may see in the wild when working with modules from the ecosystem. The alias is npm i, where i takes the place of install.

This seemingly minor alias is a small gotcha for beginners - including myself, several times when I was learning - to the Node.js and npm ecosystems, as there's not a standardized, single way that module creators and maintainers will instruct on how to install their module.


npm install <module> # Where <module> is the name of the module you want to install
npm i <module> # Where <module> is the name of the module you want to install - using the i alias for installation

Install modules and save them to your package.json as a dependency

As with npm init, the npm install command has a flag or two that you'll find useful in your workflow - it'll save you time and effort with regard to your project's package.json file.

When you're running npm install to install a module, you can add the optional flag --save to the command. This flag will add the module as a dependency of your project to the project's package.json as an entry in dependencies.


npm install <module> --save # Where <module> is the name of the module you want to install

Install Modules and Save Them to Your package.json as a Developer dependency

There's a flag that is nearly an exact duplicate, in terms of functionality, of the --save flag when installing a module: --save-dev. There are a few a key differences between the two - instead of saving the module being installed and added to package.json as an entry in dependencies, it will save it as an entry in the devDependencies.

The semantic difference here is that dependencies are for use in production - whatever that would entail for your project. On the other hand, devDependencies are a collection of the dependencies that are used in development of your application - the modules that you use to build it, but don't need to use when it's running. This could include things like testing tools, a local server to speed up your development, and more.


npm install <module> --save-dev # Where <module> is the name of the module you want to install

Install Modules Globally on your System

The final, and most common, flag for npm install that you should are the flags to install a module globally on your system.

Global modules can be extremely useful - there are tons tools, utilities, and more for both development and general usage that you can install globally to use.

To install a module from npm globally, you'll simply need to use the --global flag when running the install command to have the module install globally, rather than locally (to the current directory).

Note: One caveat with global modules is that, by default, npm will install them to a system directory, not a local one. With this as the default, you'll need to authenticate as a privileged user on your system to install global modules.

As a best practice, you should change the default installation location from a system directory to a user directory. If you'd like to learn to do this, take a peek at the seventh tip in our npm tricks article!


npm install <module> --global # Where <module> is the name of the module you want to install globally
npm install <module> -g # Where <module> is the name of the module you want to install globally, using the -g alias

Want to keep going?

If you want to keep learning about npm and all its facets, I've got a few awesome things for you. A bit ago, we shared a few npm tricks to knock your wombat socks off. Even better, we wrote a follow-up with even more npm tricks! This beginner's guide is a great springboard to get off the ground, and both of those will help you start optimizing your work with npm! If you'd like to go even further with npm and start deploying Node.js apps and npm modules into production, you should definitely take a look at NodeSource Certified Modules - it's an awesome tool that'll compliment your newly acquired npm skills!

Read More
Installing Node.js Tutorial: Windows

This article was first published in NodeSource blog on February 2017.

As with any programming language, platform, or tool that doesn't come bundled with Windows, getting up and running with Node.js takes some initial setup before you can start hacking away. In my experience, though Node.js has a far better installation experience on Windows than virtually any other language, platform, or tool that I've tried to use - just run the installer, and you're good to go.

In this quick tutorial, we'll take a look at how to get Node.js installed on Windows. Once we've completed the entirety of the tutorial, you'll be ready to take the next step with Node.js.

This guide covers installing Node.js on the following versions of Windows: Windows 7, Windows 8, Windows 8.1, and Windows 10. These are the versions that are consistently tested and supported by the Node.js build process at the time of writing.

Step 0: The Quick Guide (TL;DR) to Get Node.js Installed on Windows

Here's the abbreviated guide, highlighting the major steps:

  1. Open the official page for Node.js downloads and download Node.js for Windows by clicking the "Windows Installer" option
  2. Run the downloaded Node.js .msi Installer - including accepting the license, selecting the destination, and authenticating for the install.

    • This requires Administrator privileges, and you may need to authenticate
  3. To ensure Node.js has been installed, run node -v in your terminal - you should get something like v6.9.5
  4. Update your version of npm with npm install npm --global
  5. This requires Administrator privileges, and you may need to authenticate
  6. Congratulations - you've now got Node.js installed, and are ready to start building!

Step 1: Download the Node.js .msi Installer

As the first step to installing Node.js on Windows, you'll need to download the installer. You'll be able to grab the installer from the official downloads page for Node.js.

You'll be able to download the Windows Node.js installer by clicking the Windows Installer option at the top of the page - when you click this, you'll get an MSI installer download. Make sure to save it somewhere that you'll be able to find it!

Step 2: Run the Node.js Installer

You've got the Windows Installer - great! Now, you need to install it on your PC. The installer is a pretty typical Wizard interface for installing software on Windows - there are a few steps to it, but you can have it done in under a minute. You can get through it by following the guide below:

  • Welcome to the Node.js Setup Wizard

    • Select Next
  • End-User License Agreement (EULA)

    • Check I accept the terms in the License Agreement
    • Select Next
  • Destination Folder

    • Select Next
  • Custom Setup

    • Select Next
  • Ready to install Node.js

    • Select Install
    • Note: This step requires Administrator privlidges.
    • If prompted, authenticate as an Administrator
  • Installing Node.js

    • Let the installer run to completion
  • Completed the Node.js Setup Wizard

    • Click Finish

Step 3: Verify that Node.js was Properly installed

To double check that Node.js was installed fully on your PC, you can test the following command in your Command Prompt (regardless of if you're using cmd.exe, Powershell, or any other command prompt):

$ node -v

If Node.js was installed fully, the command prompt will print something similar to (but probably not exactly) this:

$ node -v // The command we ran - prints out the version of Node.js that's currently installed 
v6.9.5 // The printed version of Node.js that's currently installed - v6.9.5 was the most current LTS release at the time of writing.

Step 4: Update the Local npm Version

As the final step in getting Node.js installed, we'll update your version of npm - the package manager that comes bundled with Node.js.

Node.js always ships with a specific version of npm - Node.js doesn't (and shouldn't!) automatically update npm. The release cycle of the npm CLI client isn't in sync with the Node.js releases. Because of this, there's almost certainly going to be a newer version of npm available than the one that is installed as a default in any given Node release.

To quickly and easily update npm, you can run the following command:

npm install npm --global // Update the `npm` CLI client

Step 5: Go build applications, APIs, tools, and more with Node.js!

Now you've got Node.js on Windows machine. It's time to start exploring!

Luckily, we've got your back. We've written a bunch of articles to help you get started with Node.js! If you're interested in exploring ES6, you should check out our article on some of the most exciting ES6 features in Node.js. If you're interested in ways to collaborate with your team a bit better, you should check out our tutorial on using ESLint in projects to improve team collaboration through code standards. Maybe you'd just like to start deploying the applications you're about to build? In that case, take a peek at our guide on how to deploy Node.js apps on Linux with systemd!

That said, if you want to keep in touch with Node.js and the surrounding ecosystem, you should go follow @NodeSource on Twitter! We'll keep you updated with important news from the Node.js project, and share the best Node.js tutorials, guides, and tools that the community has to offer.

Read More
Installing Node.js Tutorial: macOS

Just like any programming language, platform, or library, getting up and running with Node.js takes some initial setup before you can start hacking away. With Node.js, the only initial setup required is, quite simply, getting the binary installed.

In this quick tutorial, we'll take a quick look at how to get Node.js on macOS. Once we've completed the entirety of the tutorial, you'll be ready to take the next step with Node.js.

This guide covers installing Node.js on the following versions of OS X and macOS: OS X 10.10 (Yosemite), OS X 10.11 (El Capitan), and macOS 10.11. These are the versions that are consistently tested and supported by the Node.js build process at the time of writing.

Step 0: The Quick Guide (TL;DR) to Get Node.js Installed on macOS

Here's the abbreviated guide, highlighting the major steps:

  1. Go to the Node.js Downloads page
  2. Download Node.js for macOS by clicking the "Macintosh Installer" option
  3. Run the downloaded Node.js .pkg Installer
  4. Run the installer, including accepting the license, selecting the destination, and authenticating for the install.
  5. You're finished! To ensure Node.js has been installed, run node -v in your terminal - you should get something like v6.9.4

Step 1: Download the Node.js .pkg Installer

As our first step, we need to actually get the official installer for Node.js on macOS. To do so, we can head over to the Node.js Downloads page to download the installer.

You can get the macOS installer by clicking the Macintosh Installer option - this will download the .pkg installer for Node.js. Make sure you save it somewhere that you'll be able to access it!

Step 2: Run the Node.js Installer

Now that you've got the installer downloaded, you'll need to run it. The installer is a pretty typical interface - it won't take long to get through it (under a minute), even though there are a few parts to it. You can get through it by following the guide below:

  • Introduction

    • Select Continue
  • License

    • Select Continue
    • Select Agree
  • Installation Type

    • Select Install
    • Authenticate with your Mac to allow the Installation
    • Select Install Software
  • Summary

    • Select Close

Step 3: Verify that Node.js was Properly installed

To verify that Node.js was installed correctly on your Mac, you can run the following command in your terminal:

$ node -v

If Node.js was properly installed, you'll see something close to (but probably not exactly) this:

$ node -v // The command we ran - tests the version of Node.js that's currently installed 
v6.9.4 // The version of Node.js that's installed - v6.9.4 was the most current LTS release at the time of writing.

Step 4: Update Your npm Version

As one last step for good measure, we'll update your version of npm.

Node.js always ships with a specific version of npm - Node.js doesn't (and shouldn't!) automatically update npm. The npm releases aren't synced with Node.js releases. Because of this, there's almost always a newer version of npm than the one that is installed by default with a given version of Node.

To easily update your version of npm, you can run the following command:

$ sudo npm install npm --global // Update the `npm` CLI client

Step 6: Start building with Node.js!

Now you've got Node.js on your Mac. It's time to start exploring!

Thankfully, we've got your back. We've got a ton of articles on getting started with Node.js! If you're interested in exploring ES6, you should check out our article on some of the most exciting ES6 features in Node.js. Looking for ways to standardize your JavaScript code across your team? In that case, you should check out our guide to using ESLint to build code standards in Node.js applications. Maybe you'd just like to start deploying your applications? In that case, check out our guide on deploying Node.js apps with systemd!

That said, if you want to keep in touch with Node.js and the surrounding ecosystem, you should go follow @NodeSource on Twitter! We'll keep you updated with important news from the Node.js project, and share the best Node.js tutorials, guides, and tools that the community has to offer!

Read More
Installing Node.js Tutorial: Using nvm

This article was first published in NodeSource blog on January 2017.

As with any programming language, platform, or tool, the first step to using it is getting it installed. Many of them typically come with a speedy way to upgrade when a new version is available.

By default, there's not a way to upgrade the version of Node.js you've got from within Node.js itself. That said, there's a fantastic tool for the community called nvm that allows you to manage the versions of Node.js that you've got installed locally.

One awesome aspect of nvm is that it manages the versions of Node.js, it doesn't just upgrade them. This means you can have the latest version of Node.js, the latest versions of all the LTS release lines, and any number of other versions you want to use or test as well.

In this quick tutorial, we'll take a look at how to install nvm, and then how to start using it as your version manager for Node.js. Once we've completed the tutorial, you'll be ready to take the next step with Node.js.

This guide covers installing nvm on macOS and Linux - note that all versions of Node.js may not support every version of macOS or Linux.

Step 0: The Quick Guide (TL;DR) to Get Node.js Installed using nvm

Here's the abbreviated guide, highlighting the major steps:

  • Download the nvm install script via cURL:

    • curl -o- | bash
  • Ensure that nvm was installed correctly with nvm --version, which should return the version of nvm installed.
  • Install the version of Node.js you want

    • Install the latest version with nvm install node
    • Use the latest version with nvm use node
    • Install the latest LTS version with nvm install --lts
    • Use the latest LTS verison with nvm use --lts

Step 1 (Optional): Ensure your system has the appropriate C++ compiler

In some cases, like when installing Node.js releases from their source or installing versions of Node.js before 0.8.6 (when the project started shipping binaries), you'll need to ensure that your system has the appropriate C++ build tools.

For LTS and modern releases, you will not need this step. That said, it's a nice to have to ensure that the majority of requirements are met in any scenario.

On macOS, you've got two options for a C++ compiler: the full XCode application or the stand-alone Command Line Tools portion of Xcode.

To get these on macOS, you can follow these steps:

  • Open your terminal of choice
  • Run xcode-select --install as a command

    • A popup will appear
    • Select Install
  • Allow the download to run to completion
  • If the installation went uninterrupted, you should have the necessary tools to use nvm!

On Linux, the C++ compiler will vary from distribution to distribution. For example, on Debian and Ubuntu, you'll need to install build-tools and libssl-dev, but this may be different on your given Linux distribution.

To get build-tools and libssl-dev on Debuan and Ubuntu distributions, you can run these commands:

sudo apt-get install build-essential # Install the build-essential package - let this run to completion

sudo apt-get install libssl-dev # Install the libssl-dev package - also let this one run to completion

Step 2: Download nvm with the install script

Once you've got the right C++ compiler for your system, now it's time to run the nvm install script. Here are the single-step install scripts for both macOS and Linux. You've got the option of cURL or Wget but both achieve the same result.

Note: If your Linux system doesn't have either cURL or Wget, you can run sudo apt-get install curl and use the cURL method.

Running the Install Script with cURL:

To install nvm with the cURL method, run the following command in your terminal:

curl -o- | bash

Using the Install Script with Wget:

To install nvm with the Wget method, run the following command in your terminal:

wget -qO- | bash

Step 3: Verify that nvm was Properly installed

After running the install script from Step 2, nvm should have successfully installed. To ensure that nvm is up and running on your machine, you can test it with the following command:

nvm --version

This command will return something like (though not necessarily exactly) the following:

nvm --version # The command we ran - it checks the currently installed version of nvm
0.33.0 # The current version of nvm - yours may differ!

Missing the nvm command after running the install script?

If you're using macOS, you may be missing a .bash_profile file - to troubleshoot this, you can run touch ~/.bash_profile in your command line and re-run the installer script.

If the problem persists after that, you can open the existing .bash_profile file (using your favorite text editor) and add the following line to it:

source ~/.bashrc

If you're still having issues, you can take a peek at this issue to find a discussion of the problem and a collection of possible resolutions.

Step 3: Using nvm to manage Node.js

Congratulations! You've now got nvm - a tool to easily allow you to manage and swap out the versions of Node.js you've got installed locally. Now, let's get you started with doing just that.

Install the latest Node.js version

To install the latest available version of Node.js, you can use the following command:

nvm install node

Next, to use that version of Node.js in any new shell, you can simply run the use command:

nvm use node

Install the latest Node.js LTS version

To install the latest available LTS version of Node.js, you can run the following command:

nvm install --lts

And to use that latatestTS version of Node.js in any new shell, you can simply run the use command:

nvm use --lts

Step 6: Go build applications, APIs, tools, and more with Node.js!

Now you've got a fantastic version manager for Node.js. It's time to start building!

Get unparalleled visibility into application performance and system health. Get started with N|Solid today

We've got some resources to get you kickstarted! Both the breadth and depth of the Node.js and the JavaScript ecosystems are quite large - in addition to the developer tools like NodeSource N|Solid and Certified Modules, we've got a ton of tutorials, guides, and articles to help you get kick started with Node.js.

If you're interested in keeping your code clean, maintainable, and collaborative, take a peek at our post on using ESLint for linting your JavaScript applications. Are you interested in building web applications with Node.js? One of the most challenging aspects of web apps is security - you can learn security best practices for Express to lock down your web apps, to prevent breaches and attacks. Or, maybe you want to deploy your Node.js apps with Docker? Then you should definitely read our article on dockerizing your Node.js applications.

That said, if you want to keep in touch with the Node.js ecosystem, you should follow @NodeSource on Twitter! We'll keep you updated with important news from the core Node.js project, fresh and useful Node.js tutorials, and more.

Read More
  • 3 / 3