Node.js Cluster Fork-Bomb: 400 Processes from DATABASE_URL
Over 400 Node processes on 8 cores in 20 seconds from a DATABASE_URL typo.
20+ years shipping production JavaScript and front-end systems at scale. Written from production experience, not tutorials.
- ✓Deep production experience
- ✓Understanding of internals and trade-offs
- ✓Experience debugging complex systems
- Clustering forks one Node.js process per CPU core, all sharing the same server port via the primary process.
- The primary manages the TCP socket and delegates connections to workers via round-robin (Linux/macOS) or OS-level distribution (Windows).
- Workers are fully independent V8 instances — no shared memory, so in-memory sessions break silently across workers.
- Externalize all shared state to Redis; each worker gets its own connection for sub-millisecond consistency.
- Memory overhead: ~30-80 MB per worker vs ~2-4 MB per worker thread — cluster for I/O concurrency, threads for CPU-bound work.
- Biggest mistake: calling cluster.fork() unconditionally in the exit handler creates a fork-bomb that maxes out CPU.
Imagine a busy McDonald's with one cash register — even if 10 customers arrive at once, only one gets served at a time. Node.js is that single register by default. Clustering is like opening 8 registers simultaneously, one per staff member (CPU core), so 8 customers are served in parallel. The manager (primary process) decides which register each customer joins. The customers don't know or care which register they hit — they just get served faster. That's all clustering is doing.
| Chrome | Firefox | Safari | Edge |
|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ |
Node.js is single-threaded by design. The event loop model handles thousands of concurrent I/O operations without thread management overhead — and for most API servers sitting mostly idle between database calls, that is completely fine. The problem surfaces when you provision a modern eight-core server and watch seven of those cores sit at 0% utilization while the eighth queues every incoming request behind whatever is running right now.
The cluster module was Node's answer to this problem. It forks multiple Node.js processes — one per CPU core — and has them all share the same server port. Node's own round-robin scheduler on Linux and macOS, or the OS socket-level load balancing on Windows, distributes incoming connections across workers. Each worker is a fully independent V8 instance with its own event loop, heap, and garbage collector. They do not share memory. Communication between them happens through IPC message passing, which is slower than most engineers expect the first time they measure it.
Before you reach for the cluster module, it is worth being clear about what it actually solves. The most persistent misconception is that clustering makes individual requests faster. It does not. A single request still runs on a single thread from arrival to response. What clustering improves is throughput — the total number of requests your server can handle concurrently across all cores. If your bottleneck is a slow database query that adds 200ms to every request, spinning up eight workers does nothing for that. If your bottleneck is that your single-threaded event loop cannot accept new connections fast enough because it is busy processing the previous ones, clustering will help a great deal.
I have seen teams spend weeks tuning cluster configurations before realizing their actual bottleneck was a missing index on a Postgres query. Profile first, cluster second.
This guide covers how clustering works at the socket level, the production-grade patterns for running it safely without fork-bombs or silent state corruption, the right way to debug individual workers in a live cluster, and when to reach for worker threads instead of — or alongside — clustering.
How Node.js Cluster Master-Worker Model Actually Works
Node.js clustering forks a single process into multiple workers sharing the same server port. The master process listens for incoming connections and distributes them across workers using a round-robin algorithm (on Linux) or operating system scheduling (on Windows). Each worker runs its own V8 instance, event loop, and memory space — meaning no shared state between workers without an external store like Redis or a database.
In practice, clustering gives you near-linear CPU utilization for I/O-bound workloads. A single Node.js process uses one core; on a 4-core machine, clustering with 4 workers can handle roughly 4x the request throughput. However, each worker consumes about the same memory as the original process — 30–50 MB baseline per worker. Forking 400 workers from a DATABASE_URL misconfiguration means 12–20 GB of RAM instantly allocated, likely OOM-killing the host.
Use clustering when your application is CPU-bound (e.g., image processing, JSON serialization) or when you need to saturate multiple cores for high-throughput HTTP servers. Do not use clustering for trivial I/O tasks that Node.js already handles efficiently with a single thread — you gain nothing and waste memory. Always cap workers to or a small multiple thereof.os.cpus().length
cluster.fork() count from an env var like DATABASE_URL can spawn hundreds of workers instantly — always validate and cap the number explicitly.numWorkers = process.env.DATABASE_URL.split(',').length to parallelize DB queries — DATABASE_URL had 400 comma-separated replica hosts.Math.min(parsed, os.cpus().length * 2).How Node.js Clustering Actually Works Under the Hood
When you call cluster.fork(), Node.js spawns a child process using child_process.fork() under the hood, pointing it at the same entry-point script. The cluster module injects a NODE_UNIQUE_ID environment variable into the child's environment. Workers detect this variable at startup, which is how the same JavaScript file executes completely different code paths depending on whether cluster.isPrimary evaluates to true. The entire pattern — one file, two roles — flows from this one environment variable.
The socket story is the part most engineers get wrong the first time. Normally, two processes cannot bind to the same port — the second call to bind() returns EADDRINUSE. The cluster module sidesteps this entirely. The primary process creates the actual TCP server socket and binds it to the configured port. When a worker calls server.listen(), it does not attempt to bind anything to the OS. Instead, the cluster module intercepts that call at the Node.js layer and sends an IPC message to the primary process saying, in effect, 'I want to accept connections on port 3000.' The primary responds by passing the worker a handle — not a copy of the file descriptor, but a reference to the same underlying socket object. The OS sees exactly one socket bound to port 3000. Multiple workers hold references to it and can call accept() on it.
On Linux and macOS, Node's cluster module implements round-robin distribution internally inside the primary process (SCHED_RR). The primary accepts an incoming connection and then passes it to the next worker in rotation before any application code runs. On Windows, this mechanism does not apply — the OS distributes connections after they are established, using its own scheduler, which can produce noticeably uneven distribution under bursty traffic. One worker ends up with significantly more connections than others in a pattern that looks random but is actually an artifact of how the Windows TCP stack distributes accept() calls. You can force consistent round-robin behavior on all platforms by setting cluster.schedulingPolicy = cluster.SCHED_RR before the first cluster.fork() call.
One consequence that engineers often miss until it causes an incident: if the primary process dies, it takes the socket with it. The file descriptor closes. Every worker's handle becomes invalid simultaneously. There is no graceful handoff, no socket migration to a surviving worker — the socket is gone and all in-flight connections drop instantly. This is why the primary process deserves the same production monitoring attention you give to workers, including health checks, alerting, and automatic restart via a process manager.
- Primary calls
bind()andlisten()— it is the sole owner of the actual TCP socket at the OS level. - When a worker calls
server.listen(), the cluster module intercepts the call and sends an IPC request to the primary instead of touching the OS. - The primary sends back a handle — a reference to the existing socket — not a copy of it.
- Workers can now call
accept()on that socket without ever having calledbind()themselves. - This is exactly why multiple workers can 'listen' on port 3000 without getting EADDRINUSE — only one
bind()call ever happened. - If the primary exits, the file descriptor closes and every worker's handle becomes invalid simultaneously — zero graceful handoff.
accept(), which can result in one worker handling two or three times the connections of another under bursty load — not a bug, just how Windows TCP works.fork() call is a one-liner that makes behavior consistent across platforms. Do it even on Linux to make the intent explicit to whoever reads the code next.fork() call. Without this, Windows falls back to OS-level distribution which produces uneven connection counts under real traffic patterns.Production-Grade Cluster: Zero-Downtime Restarts and Health Monitoring
The naive implementation in the previous section has one critical production flaw: it calls cluster.fork() unconditionally every time a worker exits. In normal operation this is fine — a worker crashes, you spawn a replacement, life goes on. But imagine your new deployment has a bug that crashes every worker within 200 milliseconds of startup. The exit handler fires, spawns a replacement, which crashes in 200ms, fires the handler again, spawns another, crashes again. Within 10 seconds you have hundreds of doomed processes and a host that is effectively unusable.
I have seen this pattern play out in production three separate times across different teams, and the reason it keeps happening is that the naive version works perfectly during development and staging — it only fails when a specific kind of deploy goes wrong, which is exactly when you need your infrastructure to be most resilient.
Production-grade clustering requires three things that the naive version lacks. First: restart-rate limiting with exponential backoff, so a sustained crash loop does not consume all system resources. Second: a circuit breaker that stops forking entirely after a threshold of sustained failures and alerts your on-call rotation — because more workers will not fix a configuration problem. Third: graceful shutdown so workers finish in-flight requests before exiting, enabling zero-downtime rolling restarts during deployments.
Graceful shutdown during deployments works like this: you send SIGTERM to a worker. The worker calls server.close() to stop accepting new connections while letting existing ones complete. Once all connections drain, the worker calls process.exit(0). The primary sees the clean exit — identifiable because worker.exitedAfterDisconnect is true — and forks a replacement running the new code. Repeat for each worker in sequence. Users see no interruption. This is how you deploy Node.js in production without downtime and without a load balancer reconfiguration.
cluster.worker.disconnect() or a SIGTERM you sent intentionally.Shared State Pitfalls and the Right Way to Handle Cross-Worker Data
This is where most cluster migrations fail quietly — not with crashes or errors, but with subtle correctness bugs that only surface under real load with real users. By the time they appear, they are intermittent and hard to reproduce locally.
Workers are separate OS processes. They do not share RAM. Period. An object you put into a JavaScript Map in Worker 1 is completely invisible to Worker 2. They have separate V8 heaps, separate garbage collectors, separate everything. This fact ripples through almost every stateful pattern you might have built assuming single-process operation.
Sessions: User logs in on Worker 1. Session stored in Worker 1's heap. Next request round-robins to Worker 3. Worker 3 has no record of that session. User appears logged out. No error is emitted anywhere in the system — just a redirect to the login page. In a real application with user activity across many tabs, this produces a particularly confusing experience where the user appears to be constantly losing their session.
Rate limiting: You allow 100 requests per minute per user. In-memory counter in Worker 1 shows the user has made 12 requests. But Workers 2 through 8 each show 12 requests in their own independent counters. Real combined count: 96 requests that slipped through before any worker saw a limit breach. Your rate limiter is off by a factor of 8, precisely proportional to your worker count.
In-memory caches: Each worker builds its own cache from cold independently. You get N times the cache warming time, N times the memory usage for the same data, and N potentially inconsistent views of the cached data if any worker refreshes at a different time.
The fix is always the same: externalize state. Redis is the industry standard for this because it gives you sub-millisecond latency, native data structures that map directly to common patterns, atomic operations that eliminate race conditions, and TTL-based expiry. Each worker gets its own Redis client connection — this is idiomatic and correct, not wasteful. Redis handles tens of thousands of concurrent connections efficiently. Eight workers adding eight connections is not a concern worth spending time on.
Cluster vs Worker Threads: Choosing the Right Tool for the Job
These two APIs get conflated constantly — in technical articles, in job interviews, and in pull requests. The question 'cluster vs worker threads' is often framed as a competition where one wins. They do not compete. They solve different categories of problem at different layers of the same system.
Clustering multiplies your server's ability to handle concurrent connections. Each worker gets its own event loop. Eight workers means eight event loops running in parallel, each independently accepting and processing requests. This is purely a concurrency story — you are not making any individual operation faster, you are enabling more operations to run simultaneously. The requests are still I/O-bound. They still spend most of their time waiting on databases, external APIs, or filesystem operations.
worker_threads solves a different problem: CPU-intensive computation that would block the event loop if run on the main thread. Image resizing, parsing a 10 MB JSON document, computing bcrypt hashes, video transcoding, running ML inference — these operations occupy your event loop thread for their full duration. Every other request that arrives during that time waits. Worker threads let you move that computation to a separate thread within the same process. That thread shares the V8 heap but has its own execution context and does not block the event loop from accepting new requests.
The practical differences matter for production decisions. Cluster workers are full Node.js processes — 30 to 80 MB each, full startup time, full GC overhead. Worker threads are lightweight threads within an existing process — 2 to 4 MB each, fast startup, shared GC. But that shared heap cuts both ways: an unhandled exception in a worker thread can bring down the entire cluster worker process, not just the thread. When CPU work must be fully fault-isolated — a crash in the computation must not kill the request handler — child_process.fork() is actually the right call, not worker_threads. Full process isolation, higher overhead, but a crash in the child does not propagate to the parent.
In practice, high-traffic production Node.js services that handle both heavy concurrency and CPU-intensive per-request operations typically use both: clustering for the outer concurrency layer, and worker threads within each cluster worker for the CPU-bound tasks. This is a legitimate production architecture, not premature complexity.
child_process.fork() instead of worker_threads. Full process isolation, higher overhead, but the failure boundary is clean.child_process.fork() instead of worker_threads. Full process isolation means a crash in the child cannot bring down the cluster worker. Higher overhead is the tradeoff.Debugging and Profiling Individual Workers in a Cluster
When something goes wrong in a clustered service, the debugging instinct is often to attach a debugger or take a heap snapshot at the application level. But a cluster is N independent processes, each with its own PID, its own event loop, its own memory, and its own debug port. The tools you use for single-process debugging need deliberate adaptation for this multi-process reality.
The --inspect flag cannot be shared across workers — each worker needs its own debug port. Node.js provides --inspect-port=0 to auto-assign a unique port per worker. When the primary is started with this flag, each forked worker gets its own port assigned from the OS's available port range. Node.js logs the assigned port when each worker comes online. You can then connect Chrome DevTools (chrome://inspect) or a VS Code debug session to any individual worker's port.
Heap snapshots follow the same logic. The kill -USR2 signal must be sent to a specific worker PID, not to the primary. Sending it to the primary captures the primary's heap, which contains only cluster management structures — not request-handling memory. If you configure v8.writeHeapSnapshot() in your worker code path, each worker will write its own snapshot file when it receives the signal, named with its PID for disambiguation.
For production environments where attaching a debugger is not practical, the most reliable approach is structured logging with process.pid on every log line, aggregated into a centralized log system. When a specific worker shows anomalous behavior — climbing memory, elevated error rates, slow response times — you can filter by PID in your log aggregator and reconstruct exactly what that worker was doing in the minutes before the problem appeared. This is faster and less disruptive than attaching an inspector to a live production process.
Exposing a per-worker /health endpoint that returns process.pid, process.uptime(), and process.memoryUsage() is something I add to every cluster implementation I ship. It costs almost nothing and it lets your load balancer health checks detect workers that are alive but degraded — a critical distinction that a simple TCP health check cannot make.
Why Fork Mode Is the Only Realistic Strategy
The cluster module forks child processes. Each fork is a complete copy of the Node.js runtime. That means each worker has its own event loop, its own garbage collector, and its own memory space. You get true parallelism without shared memory headaches. The master process acts as a traffic cop: it receives all incoming connections and uses a round-robin scheduler (or platform-specific logic) to distribute them to idle workers. This is not threading. This is process-level isolation. If worker 3 crashes due to a memory leak, workers 1, 2, and 4 keep serving traffic. No lock contention. No race conditions. The price is higher memory per worker. You trade memory for fault isolation. In production, you always choose isolation over shared state. Always.
Graceful Shutdown: Stop Dropping Requests on Deploy
A hard kill during deployment drops active connections. Users get 503s and your pager goes off. The fix is a graceful shutdown sequence. When the master receives a SIGTERM, it stops accepting new connections on the workers, drains existing requests, then exits. The master then forks a replacement worker. This is the zero-downtime pattern. You must listen for signal events on each worker, call server.close() to stop the listener, then wait for the active requests to finish. Use a timeout as a safety hatch: after 30 seconds, force kill. Never trust a slow request to finish. Ship a 'gracefulShutdown' helper. Wire it into your deployment pipeline. Test it with ab or wrk. If you haven't seen your app survive a rolling restart, you haven't deployed to production.
process.send() from the worker to signal readiness to die. The master can then orchestrate rolling restarts without a drop.PM2 Cluster Mode vs. Native Cluster: When to Use Which
PM2 is a popular process manager that wraps Node.js clustering with a simpler API. In cluster mode, PM2 spawns workers using the same underlying cluster module, but adds features like auto-restart, log management, and zero-downtime reload. However, PM2's abstraction hides important details: it uses a round-robin load balancer by default (on Linux), which can cause issues with sticky sessions. Native clustering gives you full control over worker lifecycle, IPC, and health checks. Use PM2 when you need quick setup and don't require custom worker logic. Use native clustering when you need fine-grained control, custom health monitoring, or integration with external orchestration tools like Kubernetes. PM2 also adds overhead: each worker process is managed by PM2's daemon, which can become a bottleneck under high churn. For production systems with complex requirements, native clustering is often the better choice.
Sticky Sessions with Socket.io in a Cluster
Socket.io relies on long-lived WebSocket connections that must be routed to the same worker for the duration of the session. In a cluster, the default round-robin load balancing breaks this. The solution is sticky sessions: the load balancer (or reverse proxy) must route all requests from a client to the same worker. With native cluster, you can implement sticky sessions by using the cluster module's and a custom load balancer that reads a session cookie. Alternatively, use a reverse proxy like Nginx with worker.send()ip_hash or a cookie-based sticky directive. For Socket.io specifically, you can use the socket.io-sticky module or the @socket.io/cluster-adapter which handles sticky sessions via the cluster module's built-in IPC. In PM2, you must set instances: 'max' and exec_mode: 'cluster' with the --sticky flag (PM2 v5+). Without sticky sessions, Socket.io will fail intermittently as handshake and subsequent packets land on different workers.
pm2 start app.js -i max --sticky to enable sticky sessions. Without this flag, Socket.io will not work correctly in cluster mode.Kubernetes + Node.js Cluster: Do You Need Both?
Kubernetes (K8s) already provides pod-level scaling and load balancing. Running a Node.js cluster inside a single pod is often redundant and can cause resource contention. The general rule: if you use K8s, let it handle scaling by running one Node.js process per pod (no cluster module). K8s will distribute traffic across pods via its service load balancer. However, there are cases where combining both makes sense: when you need to maximize CPU utilization on a multi-core node without increasing pod count (e.g., to reduce overhead of many pods). But this comes with trade-offs: you lose fine-grained per-pod health checks, and debugging becomes harder. A better approach is to use K8s horizontal pod autoscaling with single-process pods. If you must use cluster inside a pod, ensure that the pod's resource requests/limits match the total CPU cores, and that you use a readiness probe that checks all workers. Also, avoid using the cluster module's built-in load balancer; let K8s service handle it. For stateful workloads, consider using a StatefulSet with sticky sessions via session affinity.
Windows-Specific Cluster Quirks and Workarounds
Node.js clustering on Windows has several quirks due to differences in process management and IPC. First, on Windows does not support the cluster.fork()NODE_OPTIONS environment variable propagation reliably. Second, the SIGTERM signal is not available; Windows uses SIGINT or SIGBREAK. Third, the cluster module's built-in round-robin load balancer is not available on Windows; it falls back to shared socket approach, which can cause uneven load distribution. Fourth, worker restart after crash may fail if the worker exits with a non-zero code due to Windows process handling. Workarounds: use process.on('SIGINT') for graceful shutdown, and implement a custom health check that polls workers via IPC. For load balancing, use a reverse proxy like Nginx or HAProxy. Also, avoid using cluster.schedulingPolicy on Windows; it's ignored. If you need cross-platform clustering, consider using PM2 which abstracts these differences. For production on Windows, test thoroughly with the exact Node.js version and Windows Server edition.
Building a Cluster Health Dashboard with Real-Time Telemetry
A cluster health dashboard provides real-time visibility into worker status, memory usage, request rates, and error rates. The master process can collect telemetry from workers via IPC messages. Workers periodically send health metrics (e.g., memory usage, active connections, last error) to the master. The master aggregates this data and exposes it via an HTTP endpoint or a WebSocket stream. For production, use a time-series database like Prometheus for storage and Grafana for visualization. Alternatively, build a simple dashboard using Socket.io and a frontend framework. Key metrics to track: worker PID, uptime, memory (rss, heapUsed), CPU usage (via process.cpuUsage()), active handles, request count, error count, and last restart reason. Implement health checks: if a worker exceeds memory threshold or has too many errors, the master can restart it. Also, track worker death telemetry: capture exit code, signal, and any error message sent before exit. This data helps identify patterns like memory leaks or uncaught exceptions.
Worker Death Telemetry: Capturing the Why Behind Crashes
When a worker dies, the master receives an 'exit' event with code and signal. But often you need more context: what was the worker doing? Was there an uncaught exception? Did it run out of memory? To capture this, workers should install a global error handler that sends a crash report via IPC before exiting. Use process.on('uncaughtException') and process.on('unhandledRejection') to catch errors, then send a message to the master with the error stack, memory usage, and active request count. Then exit gracefully. The master can log this data and optionally restart the worker. For production, store crash reports in a centralized logging system (e.g., ELK stack). Also, monitor worker death frequency: a high rate indicates a bug or resource issue. Implement a backoff strategy: if a worker crashes repeatedly within a short time, delay restart or stop restarting to avoid a fork bomb. Use a circuit breaker pattern: track crashes per worker per minute, and if threshold exceeded, stop forking and alert.
Fork-Bomb After Bad Deploy Crashed All Production Servers
cluster.fork() unconditionally on every worker exit, no questions asked. A typo in the deployment pipeline CI step had set DATABASE_URL to an empty string instead of the actual connection string. Every worker started, attempted to establish a database connection pool during initialization, got a connection refused error, and exited with code 1. The exit handler immediately forked a replacement worker. That worker started, hit the same empty DATABASE_URL, crashed in under 200 milliseconds. The handler fired again. Each crash spawned a new process within milliseconds of the previous one dying. Within 20 seconds there were over 400 Node.js processes on a box with 8 cores. Classic fork-bomb — the kind that is entirely predictable in hindsight and entirely invisible until it happens.server.listen(). A bad config now produces a clean exit with a descriptive error message in the first 500 milliseconds of startup rather than a runtime crash that looks like an application error.- Never call
cluster.fork()unconditionally in the exit handler — always check the crash rate and apply backoff before deciding to respawn. - Implement exponential backoff for worker restarts — start at 1 second, double each time, cap at 30 seconds.
- Add a circuit breaker: if more than N workers crash within M seconds, stop forking entirely and alert immediately rather than letting the loop compound.
- Workers should validate their own startup requirements — env vars, database connectivity, required config files — before binding to the port. Fail fast with a useful error message.
- Test deployment failure modes in staging by intentionally breaking environment variables before rolling to production. This entire incident is predictable and preventable with one deliberate negative test.
cluster.fork() call to force Node's own round-robin implementation everywhere. To confirm the imbalance is real and not just perception: log process.pid alongside every request and aggregate request counts per PID in your APM tool over a 5-minute window. If the distribution is clearly non-uniform even with SCHED_RR set, the next thing to check is keep-alive connection behavior — long-lived HTTP keep-alive connections effectively pin clients to specific workers between requests.require() under the new Node.js version, a port that a previous process is still holding, or a database that is unreachable. Add restart backoff before you bring the service back up, then fix the root cause.require(). Every line of business logic belongs inside the worker code path.server.close(), fork a replacement. This keeps memory bounded without dropping traffic, and buys you the hours you need to properly trace the leak without a production incident.ps aux | grep node | grep -v grepkill -9 $(pgrep -f 'node.*cluster')| File | Command / Code | Purpose |
|---|---|---|
| io | const cluster = require('node:cluster'); | How Node.js Clustering Actually Works Under the Hood |
| io | const cluster = require('node:cluster'); | Production-Grade Cluster |
| io | const cluster = require('node:cluster'); | Shared State Pitfalls and the Right Way to Handle Cross-Work |
| io | const cluster = require('node:cluster'); | Cluster vs Worker Threads |
| io | const cluster = require('node:cluster'); | Debugging and Profiling Individual Workers in a Cluster |
| cluster-basics.js | if (cluster.isPrimary) { | Why Fork Mode Is the Only Realistic Strategy |
| graceful-shutdown.js | const SHUTDOWN_TIMEOUT = 30_000; | Graceful Shutdown |
| pm2-vs-native.js | module.exports = { | PM2 Cluster Mode vs. Native Cluster |
| sticky-socketio.js | const cluster = require('cluster'); | Sticky Sessions with Socket.io in a Cluster |
| k8s-deployment.yaml | apiVersion: apps/v1 | Kubernetes + Node.js Cluster |
| windows-cluster.js | const cluster = require('cluster'); | Windows-Specific Cluster Quirks and Workarounds |
| health-dashboard.js | const cluster = require('cluster'); | Building a Cluster Health Dashboard with Real-Time Telemetry |
| crash-telemetry.js | process.on('uncaughtException', (err) => { | Worker Death Telemetry |
Key takeaways
cluster.fork() in the exit handler is one bad deployment away from turning a configuration error into a full production outage.Interview Questions on This Topic
What is the cluster module in Node.js and what problem does it solve?
Frequently Asked Questions
20+ years shipping production JavaScript and front-end systems at scale. Written from production experience, not tutorials.
That's Node.js. Mark it forged?
14 min read · try the examples if you haven't