const blocked = require('blocked-at');
blocked((time, stack) => {
console.log(`Blocked for ${time}ms`, stack);
}, { threshold: 100 });
// Chunking a large synchronous loop across ticks
function processInChunks(items, i = 0) {
const end = Math.min(i + 1000, items.length);
for (; i < end; i++) { /* process items[i] */ }
if (i < items.length) setImmediate(() => processInChunks(items, i));
}
Topics
40
Advanced Node.js
Architecture & Design Patterns
Async Patterns
Authentication & Authorization
Authentication & Authorization (JWT, OAuth, Passport)
Background Jobs & Queues
Caching
Caching with Redis
Child Processes & Process Management
CLI Tools & Scripting with Node.js
Cloud & DevOps
Clustering & Worker Threads
Core Node.js Modules
Databases
Databases & ORMs (MongoDB/Mongoose, SQL/Sequelize)
Debugging & Diagnostics
Deployment & Process Managers (PM2)
Docker & Containerization for Node.js
Docker & Deployment
Email & Notifications
Environment Variables & Configuration
Error Handling
Event Loop & Non-blocking IO
Events & EventEmitter
Express & Middleware
File System & File Processing
File System (fs) Module
File Uploads & Media Processing
Git & Project Management
Global Objects & the process Object
GraphQL
GraphQL with Node.js
HTTP & HTTPS Modules
HTTP & Web Servers
Logging & Monitoring
Message Queues (RabbitMQ & Kafka)
Microservices Architecture with Node.js
Node.js Fundamentals & Runtime Architecture
Path & OS Modules
Performance Optimization & Profiling
Advanced Node.js
15 questions found
Event loop blocking happens when synchronous code (a large JSON.parse, a tight computational loop, a synchronous crypto operation) runs long enough to delay all other pending callbacks, timers, and I/O -- detectable via tools like the loopbench or blocked-at packages, which measure the delay between when a timer should fire and when it actually does. Prevention means offloading CPU-heavy work to worker threads, breaking large synchronous loops into chunks processed across multiple event loop ticks, and using streaming (rather than loading entire payloads into memory) for large data.
Real-world example
An API that occasionally froze for several seconds under load is traced, using blocked-at, to a synchronous bcrypt.hashSync() call on the main thread; switching to the async bcrypt.hash() variant (which offloads to the libuv thread pool) eliminates the freezes entirely.
Event Loop & Non-blocking IO;Clustering & Worker Threads
Introduced behind the --experimental-permission flag, Node's permission model lets you restrict what a running process is allowed to do -- for example, denying file system access outside specific directories, or blocking the ability to spawn child processes -- at the process level rather than relying purely on OS-level sandboxing or third-party libraries. This addresses supply-chain risk: if a compromised or malicious npm dependency tries to read arbitrary files or make unexpected network calls, a properly configured permission model can block it outright.
# Only allow file system read access to a specific directory
node --experimental-permission --allow-fs-read=/app/data server.js
# Deny child process spawning entirely
node --experimental-permission --allow-child-process=false server.js
Real-world example
A company running third-party plugin code inside their Node.js platform enables the permission model to restrict plugins to read-only access within a designated sandbox directory, containing the blast radius if a malicious or buggy plugin is ever installed.
Security;Child Processes & Process Management
How does Node.js's built-in test runner (node:test) compare to third-party frameworks like Jest or Mocha?
AdvancedNode's built-in test runner (stable since Node 20, available via node:test) provides test suites, hooks (before/after), mocking, code coverage, and a TAP-compatible reporter without any external dependency -- reducing install size and avoiding version-compatibility churn. It lacks some of Jest's more advanced features out of the box (like built-in snapshot testing or extensive matcher libraries), but for many projects it's now sufficient on its own, and can be paired with assert or a lightweight assertion library.
const { test } = require('node:test');
const assert = require('node:assert');
test('adds two numbers', () => {
assert.strictEqual(1 + 1, 2);
});
// Run with: node --test
// Or with coverage: node --test --experimental-test-coverage
Real-world example
A small internal CLI tool drops its Jest dependency entirely in favor of node:test, since the project has minimal testing needs and removing Jest cuts the node_modules install size significantly and eliminates a whole category of dependency-version conflicts.
Testing with Jest
Mocha & the Node Test Runner;CLI Tools & Scripting with Node.js
What is a memory leak in the context of a long-running Node.js server, and what are the most common causes?
AdvancedA memory leak occurs when objects that are no longer needed remain reachable from a GC root, preventing the garbage collector from reclaiming them, causing memory usage to climb steadily over time until the process crashes or is killed. Common causes in Node.js include: event listeners added repeatedly without removal (especially on long-lived EventEmitters), closures capturing large objects unintentionally, unbounded caches or arrays that grow without eviction, and timers/intervals that are never cleared.
// Leak: a new listener is added on every request, never removed
app.get('/data', (req, res) => {
eventEmitter.on('update', () => res.json(getData())); // accumulates forever
});
// Fixed: use .once(), or explicitly remove the listener afterward
app.get('/data', (req, res) => {
eventEmitter.once('update', () => res.json(getData()));
});
Real-world example
A service's memory grows steadily over several days until it's killed by the OS; heap snapshot comparison in Chrome DevTools reveals thousands of accumulated 'update' listeners on a singleton EventEmitter, traced back to a route handler that added a new listener on every request without ever removing it.
Memory Management & Garbage Collection;Debugging & Diagnostics
What are Node.js Single Executable Applications (SEA), and what are their current limitations?
AdvancedSingle Executable Applications, stable since Node 20+, let you package a Node.js application and its dependencies into a single standalone binary that runs without requiring a separate Node.js installation on the target machine -- built by injecting a compiled JavaScript blob into a copy of the Node binary itself. Current limitations include no built-in support for native addons in every configuration, larger resulting binary sizes than lightweight alternatives, and less mature tooling for cross-compiling for other platforms compared to tools purpose-built for this (like pkg or nexe historically).
# Generate a config and blob
node --experimental-sea-config sea-config.json
# Inject the blob into a copy of the node binary
node -e "require('fs').copyFileSync(process.execPath, 'myapp')"
postject myapp NODE_SEA_BLOB sea-prep.blob \
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
Real-world example
A CLI tool vendor ships their Node.js-based utility as a single executable using SEA so that end users on machines without Node.js installed can simply download and run one file, avoiding the friction of requiring them to install a Node.js runtime first.
CLI Tools & Scripting with Node.js;Deployment & Process Managers (PM2)
Showing 11–15 of 15