This single-threaded approach scales well in certain cases like for non-blocking UI or when thousands of threads incurs a cost of switching threads.
UPDATE: I originally thought the single-threaded approach was a limitation of Node and JS which prevents scaling, but it can be strength (see comment discussion), so I've updated this article.
Node achieves this through what is known as the event loop. The concurrency page on the Mozilla docs has an Event Loop section which says that it is usually implemented using a
while loop which continously checks for events to fire.
The top of that page explains that this is not typical of concurrency other languages, like C or Java. These do not have the single-threaded limitation of JS and so use multi-threading instead of an event loop.
In this talk by the Node creator, he explains in the first minute that the event loop (from the browser side) turned out to be necessary for the success of Node.
This is necessary because Node is single-threaded:
Follow the articles above for more detail on the event loop.
UPDATE: I found this series where the first article has some neat animations on the event loop - check it out.
Apache and Ruby using multiple threads but are inefficient at scale - see comment below.
Threading in Elixir is supposed to be a great strength for handling millions of requests efficiently.
New languages like Go and Rust can be very efficient at high-performance computing for modern computing tasks - in particular concurrent tasks that would be much slower in older languages.