JavaScript beyond the browser
If you're a web developer, you've probably heard of Node.js. It has become a common choice for JavaScript applications outside the browser.
Node.js is an open-source, cross-platform JavaScript runtime environment that allows developers to write server-side applications using JavaScript. But what exactly is Node.js, and why is it so popular?
The origins of Node.js
Node.js was created by Ryan Dahl in 2009 to let developers write server-side applications in JavaScript. At the time, many server stacks used blocking I/O or a thread-per-request model. Dahl instead pursued an event-driven runtime that could keep serving other work while I/O operations were pending.
To achieve this, he built Node.js on Google's V8 engine, the same JavaScript engine used by Chromium-based browsers such as Google Chrome and Microsoft Edge. Node.js pairs V8 with an event loop and asynchronous system APIs suited to server applications.
How Node.js works
At its core, Node.js uses an event-driven, non-blocking I/O model. JavaScript callbacks normally execute on one main thread, but the runtime can keep many requests in flight while network, file-system, and other I/O operations complete asynchronously. When an operation finishes, its callback is scheduled through the event loop. CPU-intensive JavaScript is different: it can block that main thread unless the work is divided, delegated to worker threads, or moved to another process.
Most standard Node.js installations include npm, a package manager for installing and maintaining third-party packages. Its registry and ecosystem make it easier to reuse libraries and publish your own. Now that we've covered enough theory, let's move on to some code.
First Node.js app
Let's create a basic web server using Node.js and Express.
1. Install Node.js
Windows:
- Visit the official Node.js website and download the latest LTS version.
- Follow the installation wizard instructions.
Linux:
- Install Node Version Manager.
- Install the latest LTS version.
1nvm install --ltsYou can verify that Node and npm are installed by entering node -v and npm -v in PowerShell or Command Prompt on Windows, or in a terminal on Linux.
2. Create a new directory
Create a new directory for your application and navigate into it:
1mkdir firstNodeApp1cd firstNodeApp3. Initialize a Node.js project
1npm init -yThis command creates a package.json manifest. It can contain project metadata, dependencies, and scripts that run during development or deployment.
The -y flag accepts npm's default values for the generated manifest.
4. Install needed dependencies
Fast, unopinionated, minimalist web framework for Node.js
- official Express.js website
Install Express by typing the following command in your terminal:
1npm install expressThe dependencies property is now present in package.json. It lists packages the application needs at runtime. The separate devDependencies field is intended for tools needed only during development or the build process.
5. Create an Express app
Now, create a file named index.js in your project directory and add the following code:
1const express = require('express')
2const app = express()
3const port = 3000
4
5app.get('/', (req, res) => {
6 res.send('Hello World!')
7})
8
9app.listen(port, () => {
10 console.log(`Express app listening at http://localhost:${port}`)
11})6. Run your app
1node index.jsNow, if you go to http://localhost:3000 in your browser, you should see "Hello World!".
You have now created and run a small Node.js application with Express.
Companies using Node.js
Node.js has been used by companies including PayPal, Uber, Netflix, and LinkedIn. One frequently cited account of LinkedIn's mobile-server migration describes reducing the server count from 30 to 3. Results from any migration depend on its architecture and workload, but using JavaScript on both the frontend and backend can simplify staffing and code sharing for some teams.
Pros of Node.js
Important advantages that may make you consider Node.js include:
-
JavaScript performance: V8 compiles and optimizes frequently executed JavaScript, which gives Node.js a capable general-purpose runtime.
-
I/O concurrency: The event loop and non-blocking APIs let one process keep many network operations in flight without assigning a JavaScript thread to every request.
-
Versatility: Node.js supports web applications, APIs, command-line tools, automation, and network services.
-
Ecosystem: A large package registry and developer community make many libraries and learning resources available.
-
Familiar language: Developers who already use JavaScript in the browser can apply the same language on the server while learning Node.js-specific APIs.
-
Shared language stack: Frontend and backend code can share types, validation rules, and tooling when both sides use JavaScript or TypeScript.
Cons of Node.js
Every technology has trade-offs, and Node.js is no exception.

Notable drawbacks of Node.js include:
-
Main-thread JavaScript execution: JavaScript callbacks normally run on one main thread, while the event loop and non-blocking I/O keep many requests in flight concurrently. CPU-heavy JavaScript can still block that event loop unless the work is moved to worker threads or separate processes.
-
CPU-intensive work needs planning: Heavy computation, such as video processing or scientific calculations, should not run for long periods on the main event-loop thread.
-
Inconsistent ecosystem conventions: The breadth and age of the package ecosystem mean libraries do not always follow the same APIs, module formats, or maintenance standards.
-
No built-in TypeScript support at the time of writing: In 2023, using TypeScript with Node.js required additional setup and transpilation.
-
Legacy callback APIs: Some standard-library APIs retain callback forms for compatibility, although Promise-based alternatives are available for many of them.
My personal thoughts
In my experience, Node.js and TypeScript provide an enjoyable development workflow. I value the language syntax, the range of packages and frameworks, the VS Code integration, and the amount of documentation available online. I have also found it straightforward to use this stack in CI pipelines and Docker images.
Conclusion
Node.js has limitations, and several come from its long commitment to backward compatibility. TypeScript, standardized ECMAScript modules, and widespread Promise-based APIs did not exist when the runtime was created, so newer approaches have had to coexist with older ones.
Newer runtimes such as Deno and Bun explore different defaults and integrated tooling. Their ideas also create useful pressure for the Node.js ecosystem to keep improving.
Node.js remains a widely used option for web development, automation, and tooling. Whether it is the right choice depends on the workload, the surrounding ecosystem, and the team's experience.
