
Node.js is an open-source, cross-platform JavaScript runtime. It runs JavaScript outside the browser on Google's V8 engine and adds access to networking, files and processes, which browser JavaScript lacks. You still write JavaScript or TypeScript. Node.js supplies the event loop, the system APIs and the package ecosystem around that code.
Teams that succeed with Node.js make two decisions well. They match it to I/O-bound workloads, and they govern it by Long-Term Support (LTS) release line. The Introduction to Node.js on nodejs.org, the project's official documentation site, describes it as an asynchronous, event-driven runtime built for scalable network applications.
Features of Node.js
Node.js has a small set of traits that explain both its strengths and its failure modes. It embeds V8, the JavaScript engine documented at v8.dev, the V8 team's official site. V8 compiles JavaScript to machine code. Node.js wraps V8 with libuv, a C library that provides the event loop and asynchronous I/O. It exposes operating-system capabilities through built-in modules such as node:fs, node:net, node:http and node:child_process.
Recent releases add features that once required third-party packages, and the Node.js 26 documentation marks each of these as stable:
- The
node:testrunner, stable since Node.js 20, covers unit and integration tests for many projects. - A global
fetch, available without a flag since Node.js 18 and stable since Node.js 21, handles outbound HTTP calls. - The permission model, enabled with the
--permissionflag, restricts file system access, network access, child processes, worker threads and native addons. It left experimental status in Node.js 23.5.0 and 22.13.0.
TypeScript support has changed too. Node.js runs .ts files directly by stripping erasable type annotations. Type stripping is enabled by default since Node.js 23.6.0 and 22.18.0, and the documentation marks it stable as of Node.js 25.2.0 and 24.12.0. Syntax that needs code generation, such as enums and namespaces that contain runtime code, still throws an error, so projects that use it need a full compiler or a tool such as tsx. Node.js 26 removed the old --experimental-transform-types flag, so check the documentation for the exact version you pin.
Node.js Development Teams
The feature set shapes who you hire. A Node.js team that writes fluent JavaScript but has never profiled an event loop will ship services that look healthy and stall under load.
The strongest teams treat the runtime as a scheduler they have to respect. They know which work belongs on the main thread, which belongs in a worker, and how to keep a large npm dependency graph current. Teams building out Node.js development capacity should screen for those skills from the first hire.
Event Loop
Node.js gets its concurrency from one main JavaScript thread. That thread hands I/O to libuv and keeps serving other events while the I/O completes. Node.js performs well when requests mostly wait on networks and databases. It degrades when a request burns CPU on that thread.
The official profiling guide (nodejs.org, accessed 2026) shows how fast this goes wrong. It profiles an example app that hashes passwords synchronously, and the benchmark output reports a mean time per request of 3,754.556 ms. The figure belongs to one teaching workload, but it shows the mechanism: while one request hashes, the event loop can accept and answer no one else.
Picture the production version. A signup endpoint hashes passwords with a synchronous call. A marketing email lands, a burst of users clicks through at once, and every request on that instance queues behind the hashing. The health check endpoint queues too. The orchestrator marks the pod unhealthy and restarts it, dropping every in-flight request. The on-call engineer sees CPU saturation and no errors in the logs.
The documentation points to the fix: move CPU work off the loop. The asynchronous crypto APIs hand hashing to libuv's worker pool. Heavier custom computation can move into worker_threads, which run JavaScript in parallel threads, each with its own V8 instance and event loop.
The Node.js diagnostics guide on poor performance starts from high latency that you have already ruled out as a database or downstream problem, and then profiles for the code that consumes the most CPU cycles. A process can stay alive while a blocked event loop stops it from making progress. Health checks pass, dashboards show a running process, and requests time out anyway.
Single-threaded execution also changes the concurrency problems you inherit. One event-loop thread avoids most shared-memory locking, because two callbacks never run at the same instant. Race conditions still occur through async interleaving. Two requests can each read a value, await a database call and write back stale data. You drop mutexes from daily work and keep the job of reasoning about ordering.
A reasonable objection: libuv already runs a thread pool, worker_threads exist, and clustering uses every core, so the single-thread limitation sounds outdated. The mechanics are real. libuv uses a worker pool for some file system, DNS and crypto operations, and worker_threads, child processes and the node:cluster module let an application spread work across cores. Using more cores still takes an explicit design decision, because ordinary callbacks run on one event-loop thread by default. Decide early which work stays on the loop, which goes to workers or separate processes, and which belongs in a job queue.
Callbacks, Promises and async/await
Callbacks came first. You pass a function to an operation, and Node.js calls it when the operation finishes, conventionally with an error as the first argument. Deeply nested callbacks became hard to read and harder to debug.
Promises replaced that nesting with chainable results and a single error path. async/await is standard in modern JavaScript and documented on MDN, Mozilla's web developer reference. It lets you write Promise-based code in a straight-line style with ordinary try/catch blocks. Most Node.js core modules now offer Promise versions, such as node:fs/promises.
All three forms schedule work on the same event loop, and the main thread executes all of it. An await on a database call yields the thread to other requests. An await on a function that crunches numbers yields nothing, because the crunching happens before the Promise resolves. Asynchronous syntax leaves CPU work exactly as blocking as it was.
That distinction decides whether a service scales. Rewriting callbacks as async/await improves readability and error handling while throughput stays flat. Moving the CPU-bound step to a worker changes throughput.
Error handling is where async code most often fails in review. An unhandled Promise rejection terminates the process by default in current Node.js versions, so every await path needs a catch at the right level.
Node.js Libraries and npm
npm is Node.js's biggest productivity advantage and its largest attack surface. A team that adopts packages without committed lockfiles, reproducible installs and automated dependency updates takes on supply-chain risk it has not measured.
The W3C, the web standards body, documents its Node.js setup. The stack uses npm, ESLint with an Airbnb-based config, Mocha, React and Express. It also recommends Dependabot, GitHub's automated dependency-update service, to receive dependency updates and security fixes. A standards body paired its framework choice with automated dependency governance.
The install-level controls are cheap. Commit the lockfile and install with npm ci, which installs exactly what the lockfile records and fails if package.json disagrees. The Node.js security best practices guide covers the application side, including malicious third-party modules and dependency confusion. Validate all input, use parameterized queries, avoid eval, and isolate externally supplied code in a separate process or sandbox.
A fair objection holds that supply-chain risk is overstated, since PyPI, Maven and NuGet carry the same category of exposure. Concede it. The gap is governance, and the controls cost little compared with the exposure. A committed lockfile, npm ci and automated updates make up the core of what the W3C setup recommends.
For larger codebases, two frameworks sit alongside the libraries below. NestJS adds modules, decorators and dependency injection, and earns its weight when many engineers share a codebase. Fastify emphasizes throughput and schema-based validation for performance-sensitive APIs. Our pages on Express.js development and NestJS developers cover framework work in more depth.
Express
Express is the minimal HTTP framework most Node.js developers learn first. It gives routing and middleware with little else, which suits small services where a few people hold the whole design in their heads. Its middleware ecosystem is large, so the same dependency discipline applies.
Socket.IO
Socket.IO handles real-time, bidirectional communication between clients and servers. It runs over WebSockets with an HTTP long-polling fallback and adds rooms, acknowledgements and automatic reconnection. Chat, live dashboards and collaborative editing are typical uses.
Mongoose
Mongoose models MongoDB data with schemas, validation and middleware hooks, which gives structure to a schemaless database.
Webpack
Webpack is a module bundler that runs on Node.js. It packages browser code and assets for the front end, and server-side services rarely need it.
Babel
Babel compiles newer JavaScript syntax for older environments. Its server-side role has narrowed, because modern Node.js supports current JavaScript syntax and can strip TypeScript types natively. Babel still matters for front-end builds and for syntax proposals that engines have not shipped.
Async
The Async library once tamed callback-heavy control flow with helpers for series, parallel and queue patterns. Native Promises and async/await have largely superseded it, and new code rarely needs it.
Passport
Passport is authentication middleware for Express-style apps, with strategies for local login, OAuth providers and single sign-on. Pin and update its strategy packages with care, because that code sits directly on your security boundary.
Every package you skip is one you never have to patch. That is why the built-in test runner, fetch and permission model matter as much as any library here.
Node.js Use Cases
Node.js is the right default for I/O-bound services: web apps, APIs, data streaming, real-time chat, LLM-backed chatbots and microservices. For CPU-bound or numerically heavy services, Python, Java or C# is usually the better fit. Compare options workload by workload.
Adoption is broad. In the Stack Overflow Developer Survey 2026, 4,769 of 10,281 respondents (46.4%) reported extensive development work with Node.js in the past year. React drew 4,265 respondents (41.5%) and Next.js 2,117 (20.6%) on the same denominator.
A reasonable objection: those numbers mostly show that JavaScript is unavoidable in the browser. Accept it. The figure measures adoption, not fitness. The fitness case rests on workload logic: a request that mostly waits on a database or an upstream API gains little from extra threads and a lot from a runtime that keeps serving other connections during the wait.
Web Applications
Server-rendered sites, single-page app backends and backend-for-frontend services fit Node.js directly. The MEAN stack (MongoDB, Express, Angular and Node.js) shows how far full-stack JavaScript extends: one language from browser to database, with shared validation logic and types on both sides.
Data Streaming
Node.js streams move data through a pipeline in chunks, so a large file, log feed or media upload never has to sit fully in memory. Backpressure is built in: a slow consumer signals the producer to pause. Streams suit ETL steps, file processing and proxying between services.
Real-Time Chat and Chatbots
Real-time chat runs over WebSockets, where many mostly idle connections impose little per-connection event-loop work. AI chatbots follow the same I/O-bound pattern. A Node.js service receives a user message, calls an LLM API such as ChatGPT or Claude, and streams tokens back to the client over HTTP or WebSockets. Nearly all of the request's wall-clock time goes to waiting on the model, so one instance holds many conversations open at once. Our write-up on AI chatbots covers the product side.
APIs
Node.js commonly powers REST and GraphQL APIs. JSON is native to JavaScript, so serialization adds little code complexity, and frameworks like Fastify validate request schemas at the edge.
Microservices
Small Node.js services start fast and use modest memory, which suits container platforms. The risk is sprawl: each additional service multiplies dependency trees and LTS upgrades. Pairing Node.js services with cloud-native and DevOps practices keeps mixed estates deployable.
Node.js vs Other Backend Technologies
Pick per service, based on what each one spends its time doing. Production systems often combine runtimes: a Node.js API layer can sit next to a Python data service and a Java or C# core.
Within JavaScript runtimes, Deno and Bun are the main alternatives in 2026. Ryan Dahl created Deno as well as Node.js. Deno uses secure-by-default permissions and supports URL and file-path module references alongside npm packages. Node.js keeps ecosystem scale and published LTS windows.
| Runtime | Concurrency model | Strongest fit |
|---|---|---|
| Node.js | Single event loop plus worker pool | I/O-bound APIs, real-time, streaming |
| Python | asyncio, multiprocessing | Data, ML, numeric work |
| C# / .NET | Multithreaded, async/await | Mixed I/O and CPU load |
| Java | Mature multithreading | Long-lived, CPU-heavy enterprise systems |
| PHP | Request-per-process | Content-driven web apps |
Python
Python has asyncio for asynchronous I/O and a deeper numerical and machine-learning ecosystem. Teams doing model training, data analysis or heavy numeric work usually reach for Python, and a Python service that mostly waits on I/O can use asyncio for the same non-blocking style Node.js uses.
C#
C# has had async/await since C# 5.0, documented in the asynchronous programming guide on Microsoft Learn, Microsoft's official developer documentation. The .NET runtime spreads work across a managed thread pool, which makes it a strong fit for services that mix I/O with real CPU load.
Java
Java offers mature multithreading, a large enterprise ecosystem and established tooling for long-lived systems. Where one process must run substantial CPU work across many cores, Java handles it without extra architecture.
PHP
PHP remains common for web applications. It suits content-driven sites and request-per-process hosting, where each request starts clean and shares no memory with the next. Node.js keeps state in a long-running process, which helps with WebSockets and hurts if a memory leak goes unnoticed.
Goals of Node.js
The project states its purpose on nodejs.org: an asynchronous, event-driven JavaScript runtime designed to build scalable network applications. Nearly every design choice follows from that goal, from non-blocking I/O to streams.
Node.js is a project of the OpenJS Foundation, which hosts JavaScript projects including Node.js, webpack and Express. Technical direction sits with the project's Technical Steering Committee, and the Release working group publishes the schedule teams plan against.
That schedule is the practical guarantee. Node.js 26 "Lithium" entered Long-Term Support with v26.13.0 on October 28, 2026, which makes it the current Active LTS line. The project's GitHub releases page shows v24.22.2 "Krypton" shipping on October 28, 2026 and v22.23.4 "Jod" on October 21, 2026, both as LTS maintenance releases.
| Line | Codename | Status (Nov 2026) | End of life |
|---|---|---|---|
| Node.js 26 | Lithium | Active LTS | April 30, 2029 |
| Node.js 24 | Krypton | Maintenance LTS | April 30, 2028 |
| Node.js 22 | Jod | Maintenance LTS | April 30, 2027 |
Sources: Node.js release schedule and Node.js releases page, accessed November 2026. Node.js 20 "Iron" reached end of life on April 30, 2026.
The schedule itself is changing. Node.js v27.0.0-alpha.0.0.0 shipped on October 29, 2026. Starting with Node.js 27, the releases page says the cycle becomes annual: each major spends six months in Alpha, then six months in Current, and then every major moves to LTS, not only even-numbered ones. The Release working group lists LTS for Node.js 27 starting October 20, 2027. Alpha builds are meant for library authors and CI pipelines, not production, so an engineer who sees "27" and assumes it suits a new project will put a service on a line with no LTS guarantee.
Node.js and Mobile App Development
Node.js serves the backend APIs that iOS and Android clients call: authentication, push-notification triggers, sync endpoints and real-time updates over WebSockets. A mobile backend spends most of its time waiting on databases and third-party services, so the same I/O-bound profile applies.
Node.js also runs the development tooling for React Native, including the Metro bundler and the CLI. The mobile app itself ships as a native app, while Node.js powers the build pipeline and the server behind it.
How to Hire Node.js Developers
Knowing where Node.js fits only helps if the version you run is still supported and the people you hire know how to keep it that way. Teams that run a Node.js line past its end of life carry unpatched risk, so picking an LTS line and planning upgrades around the published schedule matters more than any framework decision.
A fair objection treats release-line governance as an ops chore any competent developer can handle. Changing the configured version number is the easy part. The hard part is regression testing across a major-version upgrade: native modules must rebuild, dependencies drop support for old versions, and someone has to know which line production may run.
On engagements we have run, the first thing we check is which Node.js line production is pinned to and whether event-loop delay is monitored. A team that does both already has the habits that keep a service patched and responsive. Screen candidates on four things:
- The LTS upgrade process
worker_threadsuse- npm governance
- Async error handling
Ask how they would move a service from Node.js 22 to Node.js 26, and listen for a test plan. Ask where they would put a CPU-heavy task, and listen for worker_threads, a separate process or a job queue. Ask how they keep dependencies current, and listen for lockfiles, npm ci and automated updates. A candidate who cannot explain why wrapping a hash in a Promise leaves the loop blocked will build the service that times out while its health check passes.
Is a Node.js Developer Budget Friendly?
Node.js developer cost depends on scope and team model. A small API needs a different seniority mix than a multi-service platform, and in-house hires, contractors and nearshore engineers each price differently.
A narrow, well-bounded service can run on mid-level engineers with a senior reviewer. A platform with multiple services, real-time connections and CPU-bound tasks needs engineers who have already made the event-loop mistakes once. Price the scope before comparing rates.
Nearshore teams change the arithmetic on coordination. Our engineers sit in 20+ Latin American countries and work in US time zones, so code review, incident response and planning happen in the same working day. Teams that want to hire nearshore Node.js developers should budget for the unglamorous work too: upgrade testing, dependency updates and event-loop monitoring. Skipping those line items moves the cost into the next incident.
JavaScript Everywhere
Node.js made JavaScript a full-stack language. The same language now runs in the browser, on the server, in build tooling and in the React Native development workflow, and TypeScript types can flow across all of them. One language lowers the cost of moving engineers between front end and back end and lets teams share validation code and data types across the stack.
That reach only pays off if the server side stays healthy. Pin Node.js 26 "Lithium" in .nvmrc or your container image. If a service stays on 24 or 22, write down why and when it moves. Then pick one real I/O-bound endpoint, load-test it with event-loop delay monitoring on, and read the numbers before you commit another service to the runtime. If the loop stays responsive under load, you have your answer. If it stalls, you found the CPU-bound step before your customers did.
Frequently Asked Questions
Is Node.js a framework or a programming language?
Node.js is neither a framework nor a programming language. It is an open-source, cross-platform runtime that executes JavaScript outside the browser using Google's V8 engine, and it adds operating-system access for networking, files and processes. Frameworks such as Express, NestJS and Fastify run on top of Node.js. The language you write remains JavaScript or TypeScript.
Which Node.js version should I use in 2026?
For production in late 2026, use Node.js 26 "Lithium". It entered Long-Term Support with v26.13.0 on October 28, 2026, and the Node.js release schedule lists end of life on April 30, 2029. Node.js 24 "Krypton" and 22 "Jod" are Maintenance LTS lines that suit compatibility needs, with end of life on April 30, 2028 and April 30, 2027. Node.js 27 is an Alpha line intended for testing, not production.
Is Node.js single-threaded?
Node.js runs your JavaScript callbacks on one main event-loop thread, which is why people call it single-threaded. It is not limited to one CPU core, though. libuv uses a worker pool for some file system, DNS and crypto operations. worker_threads, child processes and clustering let an application spread CPU work across multiple cores.
Can Node.js run TypeScript directly?
Yes, for erasable syntax. Node.js strips type annotations by default since versions 23.6.0 and 22.18.0, and the documentation marks type stripping stable. Enums and namespaces with runtime code still need a compiler or a tool such as tsx.
Is Node.js good for CPU-heavy work?
Node.js is a weak default for sustained CPU-heavy work on the main thread. Long computations, such as synchronous password hashing, block the event loop and delay every other request. Wrapping CPU work in a Promise leaves it on the main thread and keeps the event loop blocked. Teams move CPU-bound tasks to worker_threads, separate processes, job queues or a service written in another runtime.
Should I choose Deno or Bun instead of Node.js?
Deno was created by Ryan Dahl, who also created Node.js. It emphasizes secure-by-default permissions and a module model that depends less on npm. Bun is another JavaScript runtime that teams evaluate as an alternative. Node.js keeps the advantages of ecosystem scale and published LTS support windows. Compare all three on your own workload, dependencies and support requirements.
Build Your Node.js Team With Azumo
Azumo is a SOC 2-certified nearshore software development company founded in 2016, with engineers in 20+ Latin American countries working in US time zones, 100+ customers and a 4.9 rating on Clutch. We build and staff Node.js services, from the first API to multi-service platforms on a governed LTS line.
Tell us about your product and we will put together a Node.js team in your time zone, or see our Node.js development services.

.avif)



