Node.js basics and how to use them
In the span of a little more than a decade, Node.js has become the single most common technology used in professional web development. For developers working in the JavaScript ecosystem, the chances are good they're using Node. And for anyone building high-performance web applications, Node is nearly a requirement.
Node’s ubiquity is due in part to its architectural approach, which puts it leagues ahead of other languages in terms of performance. Ease of use is another contributing factor. Because Node uses JavaScript, web developers can focus on honing existing skills rather than learning a second server-side language. Lastly, Node comes bundled with npm, which is a command-line package management tool as well as the largest library for JavaScript tools and software.
For new coders and veteran developers alike, this guide serves as a complete introduction to Node and many of its features, including why it’s an excellent choice for server-side applications. Readers will also learn how to spin up local Node projects and add dependencies to them so they can start building high-performance apps of their own.
What is Node.js?
Node.js is an open-source JavaScript runtime environment made for the server. Rather than using a language like Python or PHP, Node allows developers to leverage their existing skills on the server as well as in the browser. Released in 2009 by Ryan Dahl, it’s since become one of the most popular web development platforms in the world.
In practice, Node is more than a JavaScript runtime environment. Because it uses npm as its default package manager, it's the de facto platform for any and all types of software development involving web technologies. This means developers working on the front end of the web use Node just as much as those on the back end. Meanwhile, developers can also use Node to build micro services and micro front-ends.
Node also reaches beyond web browsers. The popular Electron framework, which lets developers write cross-platform applications using web technology, also uses Node. Apps like VS Code, Discord, Slack, and countless others use Electron, meaning Node is running on many people's computers without them even knowing.
Whether it's the back end for a high-performance web app, a local development environment, or a cross-platform desktop app, Node is a versatile platform for anyone developing software using JavaScript. Coupled with easy access to the largest software registry in the world, it should come as no surprise that Node is the most popular web development platform in existence.
The benefits of using Node.js
For those looking to learn web development, Node is an industry-standard that powers some of the world’s most popular apps, both on and off the web. But Node's flexibility is only part of the reason it's so popular — as a development platform, it provides a long list of benefits to JavaScript developers.
Async programming
One of the key features of Node.js is that it’s engineered with an event-driven, non-blocking I/O architecture, which gives it the ability to process numerous tasks on a single thread without blocking the main thread. This asynchronous approach allows it to process a variety of tasks, handle large quantities of data, and respond to multiple requests — all simultaneously. For apps built on Node, this translates into high performance and efficiency that scales exceedingly well.
Node.js leverages the event loop and makes use of callbacks, promises and the async/await syntax to manage task execution. What makes Node unique is that it uses the loop as a runtime construct rather than a library. Node enters the loop once it executes input scripts and, once no other callbacks are pending, it exits the loop.
In synchronous programming, applications must wait for one task to complete before starting another. While this is usually unnoticeable things like desktop applications for a single user, performance falters once there are thousands of requests and large amounts of data involved. By leveraging an async approach, Node ensures that the physical characteristics of the server are the only bottlenecks
Engineers can take full advantage of Node’s performance by using the same callbacks, promises and async/await functionality that’s part of JavaScript. Incidentally, they can expect the same results in terms of performance, where callbacks are better for simple implementations, while promises and async/await are tailored more toward operations within complex applications.
Event handling
Node’s event-driven, asynchronous approach means event handling is a key aspect of its architecture. In a Node application, things like downloading a file, retrieving information from a database, or a simple connection request all trigger an event. To process events, Node uses its event loop as a runtime construct rather than a library, which is the typical approach.
Instead of triggering the event loop, Node receives an event, steps into the concurrent event loop, and exits the loop once there are no more callbacks to perform. This is how JavaScript functions in a web browser, and it’s a big part of Node’s performance as well as its capabilities as a platform for streaming web apps.
Modularity
Another of Node’s benefits is its ability to break JavaScript code into self-contained files to improve the structure of codebases. This allows developers to better organize their code into separate components, which they can then import across their project.
In practical terms, modules are standalone JavaScript files. This approach allows developers to break specific functions, such as an API request or access to a database, into separate files to declutter application code. Later, they can import the module when they need to access the resource.
Modules are also essential when working with component-based frameworks, like React, Vue or Svelte. By breaking individual components into separate files, complex web apps are infinitely easier to organize and maintain, especially when a team of developers is involved.
Node.js popularized the use of CommonJS, one of the first module systems used for JavaScript. Since then, JavaScript added its own syntax for modules, called ESM (ECMAScript Modules). Node supports both CommonJS and ESM, though ESM is aligned more closely with the browser.
Performance
Node's event-driven, asynchronous approach is why it's so high performing. But Node’s architectural implementation also utilizes a single, non-blocking thread, meaning developers don’t have to worry about deadlocked processes. Node handles requests concurrently, which is a significant factor in its high performance. And it’s why Node is a great solution for high-throughput web apps.
Another reason Node is so performant is that it uses Google’s open-source high-performance V8 JavaScript engine under the hood. The V8 engine in Node is responsible for processing JavaScript code in the same way a browser would. And in fact, V8 is the same engine that powers JavaScript in Google Chrome, so it’s no slouch. Incidentally, Node benefits from the continuous improvements added by the V8 team.
Setting up Node.js
You can download and install Node directly from the Node.js website, though it’s best practice to use a version manager. This approach avoids potential problems with permissions on the system, and it allows developers to easily manage multiple Node installations across projects.
The most popular version manager is nvm, also known as Node version manager. Using nvm makes it simple and quick to install different versions of Node.js and switch between them depending on the project’s requirements.
Windows users can install nvm via the installer found on the GitHUb repository. Users on Linux or macOS can install nvm via the terminal:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
# or
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
Once nvm is installed, you can install the latest long-term support (LTS) version of Node.js from the terminal by typing:
nvm install LTS
To install different versions of Node and switch between them, you simply use the above command along with the required version number along with the nvm use command. For example:
nvm install 16
nvm use 16
Now using node v16.9.1 (npm v7.21.1)
Once Node is installed, you can verify everything works by opening up a command line or terminal and typing node -v, which will return the version you installed. Developers can also test out JavaScript code using Node’s Read-Eval-Print-Loop. The REPL is an interactive command-line interface provided by Node.js that evaluates JavaScript code directly. It’s a convenient way to experiment and test JavaScript code without spinning up a development environment.
To start the Node REPL, simply type node in the terminal followed by the return key. From this prompt, you can write JavaScript code and see the results of your expressions in real time. To exit the Node REPL, press Ctrl + C twice or type .exit and hit return.
Node package manager
Node Package Manager, commonly known as npm, is the default package manager that comes with Node.js. Many people tend to associate Node and npm closely, but they’re actually independent projects. Introduced in 2014, npm was developed by npm, Inc. as an open-source toolkit designed specifically for Node.
Npm serves multiple purposes: it acts as a package manager, a software registry, and a command-line tool for accessing the registry. In general, package managers like npm facilitate the process of organizing modules in a way that Node.js can easily locate them. Furthermore, npm handles dependencies and resolves potential conflicts that can arise during the installation and management of packages.
While npm is the de facto standard for managing Node projects, there are other popular package managers with wide support, including Facebook’s yarn and the open-source pnpm project. These tools have slightly different approaches for managing Node projects, though they can still access npm’s vast library. While this guide uses npm for the sake of convention, the information covered generally applies to these other tools.
It’s worth mentioning that using npm — and Node in general — requires comfortability working from the command line. Even if developers aren’t used to working in a terminal window, the following commands shouldn’t be overwhelming. And because the command line is essential in web development, it’s a good skill to start learning.
To make a new project, open up a terminal or command line interface and navigate to a directory used for projects. Next, create a directory for a new application, navigate into it and initialize it as a Node.js project using the init command:
npm init
This will prompt you for your project’s details, including its name, version number, and GitHub repo. For the purposes of this guide, you can hit return to accept each of the default values.
Once initialization is complete, npm generates a package.json file in the project directory. This file serves as the metadata for a Node project, a repo for project-specific scripts and a manifest for npm packages. For example, when you install a package, npm updates this file with the corresponding dependency and version information. You can also edit it manually with a text editor.
Installing packages
Building applications with Node means fast and simple access to more than a million open-source packages within the JavaScript ecosystem. If there’s some specific functionality you need for an app or a development workflow, there’s a good chance it’s available via npm.
Since you’ll need one to test your projects in the browser, a web server makes for a great first package to install. The open-source fastify framework allows you to easily spin up a web server for any project with just a few lines of code. To install it, type:
npm install fastify
Next, in your project directory, create a server.js file and add the following code:
// Require the framework and instantiate it
const fastify = require('fastify')({ logger: true })
// Declare a route
fastify.get('/', async (request, reply) => {
return { hello: 'world' }
})
// Run the server!
const start = async () => {
try {
await fastify.listen({ port: 3000 })
} catch (err) {
fastify.log.error(err)
process.exit(1)
}
}
start()
You can now start a performance web server for your new app by typing node server from your project directory.
By default, npm installs packages as project dependencies and adds package details to the package.json file. However, if you only need the package during development, such as a testing library, you can install it as a development dependency. This prevents unnecessary code from shipping to production. Install jest, the JavaScript testing framework, using the --save-dev flag:
npm install jest --save-dev
Finally, you can also install npm packages globally to them available as an environment variable in your terminal. For example, if you want to have a fast and simple web server on-hand from any directory on your computer, you can install fastify globally with the --global or -g flag.
Updating packages
Alluded to earlier, the package.json file plays a key role in dependency management, including keeping them updated and properly versioned. Dependencies within the package.json file are expressed through semantic versioning (semver) constraints, which determine which versions are installed for each package. For example, after installing fastify, you’ll see these lines added to your package.json file:
"dependencies": {
”fastify”: “^4.14.1”`
}
The number value in the fastify key indicates the version number. The tilde in front of the value, npm will only update the package to version approximately equivalent, which means anything less than 4.2.0. Meanwhile, if a version has a caret character in front of it, such as `”4.14.1’, npm will update to any version other than major releases. In other words, anything less than 5.0.0.
In addition to semver, it is essential to be aware of the package-lock.json file, which serves as the true representation of installed dependencies. You can read more information about semver and package locks in the npm documentation.
To update npm packages, you’ll want to first run the npm outdated command, which provides a list of available updates, indicating which packages will be updated. This ensures you’re aware of changes before initiating them. There are also tools that can automate the update process through Github apps, as long as developers have trusted and comprehensive tests in place.
If you’re updating manually, it’s best to update each package individually. To do so, you simply type npm update followed by the package name. For example:
npm update fastify
Keep in mind, it’s essential to update packages cautiously by testing them in a development environment first. Keeping packages updated is important, but should always be done carefully.
Uninstalling packages
Finally, there are occasions when developers need to uninstall packages. Keep in mind, uninstalling packages requires the same consideration that updating them does. If an app's codebase references or depends on functionality from a package and that package is uninstalled, it will likely break the application.
Following the same pattern as installs and updates, you can uninstall packages with the npm uninstall command. To uninstall ESLint, type:
npm uninstall eslint
Harnessing the power of Node
It’s difficult to overstate the countless benefits that Node affords to any developer working with web technologies. With its asynchronous programming model, event-driven architecture, and modular design, Node is a top-tier solution for developing performance applications that scale exceptionally.
It’s no less valuable as a platform for local development. In addition to its inherent benefits as a JavaScript runtime, Node’s coupling with npm means web developers working in other areas have access to an infinite number of packages that streamline workflows, add quality-of-life improvements, and provide access to next-generation browser features without the next-generation browser.
These are just a few of the many benefits you’ll gain by installing Node and using npm to develop high-performance apps. Regardless of the precise project goals, the one certainty is that, if you’re building for the web, Node is one of the best tools you’ll use.