1. How does Node.js schedule tasks internally?
Node.js schedules tasks using the event loop, microtask queues, and libuv.
Scheduling priority:
-
process.nextTick()queue (highest) - Microtasks (Promises)
- Event loop phases (timers, I/O, check, etc.)
Flow:
- Synchronous code runs first
- Then microtasks
- Then event loop handles async callbacks
Example:
setTimeout(() => console.log("timeout"), 0);
Promise.resolve().then(() => console.log("promise"));
process.nextTick(() => console.log("nextTick"));
Output:
nextTick
promise
timeout
2. How does Node.js manage memory?
Node.js uses the V8 engine to manage memory automatically.
Memory areas:
- Stack → stores primitive values and function calls
- Heap → stores objects and complex data
Key points:
- Automatic allocation and deallocation
- Uses garbage collection
- Limited heap size (can be configured)
3. How does garbage collection work in Node.js?
Garbage collection (GC) in Node.js is handled by the V8 engine.
Mechanism:
- Uses Mark-and-Sweep algorithm
Steps:
- Identify reachable objects
- Mark them as active
- Remove unreferenced objects
Generations:
- Young generation (short-lived objects)
- Old generation (long-lived objects)
4. How does garbage collection impact performance?
GC can pause execution, affecting performance.
Effects:
- CPU overhead
- Latency spikes
- Event loop delays
Example scenario:
- Large memory allocation → frequent GC → slower response time
Optimization:
- Reduce object creation
- Avoid memory leaks
- Use efficient data structures
5. How do you detect memory leaks?
Techniques:
- Monitor memory usage
console.log(process.memoryUsage());
- Heap snapshots
- Chrome DevTools
-
node --inspect
- Tools
- heapdump
- clinic.js
Signs:
- Increasing memory over time
- Slow performance
6. Difference between heap and stack memory
| Stack | Heap |
|---|---|
| Stores primitives | Stores objects |
| Fast access | Slower access |
| Fixed size | Dynamic size |
| Managed automatically | Managed by GC |
7. How do you tune Node.js memory limits?
Node.js has a default memory limit (~1.5–2GB).
Increase memory:
node --max-old-space-size=4096 app.js
Meaning:
- 4096 MB heap size
When needed:
- Large applications
- Data-heavy processing
8. What is WASI and why was it introduced?
WASI (WebAssembly System Interface) is a standard that allows WebAssembly to interact with the system outside the browser.
Purpose:
- Run WebAssembly on servers (like Node.js)
- Provide system-level access (files, network)
Benefit:
- Secure sandboxed execution
- Cross-platform compatibility
9. What is Punycode in Node.js?
Punycode is a method to encode Unicode domain names into ASCII.
Example:
- Domain:
müller.com - Punycode:
xn--mller-kva.com
Use case:
- Internationalized domain names (IDN)
Node.js provides a punycode module (now deprecated but still relevant conceptually).
10. How do you optimize a high-traffic Node.js API?
Key strategies:
1. Use clustering
- Utilize multiple CPU cores
2. Caching
- Redis or in-memory cache
3. Load balancing
- Distribute traffic
4. Optimize database queries
- Indexing
- Query optimization
5. Use async operations
- Avoid blocking code
6. Compression
const compression = require('compression');
app.use(compression());
7. Rate limiting
- Prevent abuse
8. Monitor performance
- Logs, metrics
11. How do you handle CPU-intensive tasks?
CPU-intensive tasks can block the event loop, so they must be offloaded.
Approaches:
- Worker Threads
- Child Processes
- External services (microservices)
Example (Worker Thread):
const { Worker } = require('worker_threads');
new Worker(`
let sum = 0;
for (let i = 0; i < 1e9; i++) sum += i;
console.log(sum);
`, { eval: true });
Key idea:
Keep the main thread free for handling requests.
12. How do you measure async operation performance?
Methods:
- performance API
const { performance } = require('perf_hooks');
const start = performance.now();
setTimeout(() => {
console.log(performance.now() - start);
}, 100);
- process.hrtime()
const start = process.hrtime();
// operation
const diff = process.hrtime(start);
console.log(diff);
- Logging and monitoring tools
13. Which metrics should be monitored in production?
Key metrics:
- CPU usage
- Memory usage
- Event loop lag
- Response time
- Throughput (requests/sec)
- Error rate
- Database latency
Example:
console.log(process.memoryUsage());
14. How do you profile a Node.js application?
Tools:
- Built-in profiler
node --inspect app.js
- Chrome DevTools
- CPU profiling
- Heap snapshots
- Clinic.js
- Flame graphs
- Bottleneck detection
15. What is load shedding?
Load shedding is a technique where the system intentionally rejects some requests to maintain stability under heavy load.
Example:
- Returning HTTP 503 when overloaded
Purpose:
- Prevent system crash
- Maintain performance for critical users
16. How do you handle traffic spikes?
Strategies:
- Load balancing
- Auto-scaling
- Caching (Redis)
- Rate limiting
- Queueing systems (RabbitMQ)
17. How does Redis improve Node.js performance?
Redis is an in-memory database used for caching.
Benefits:
- Faster data access
- Reduces database load
- Improves response time
Example:
const redis = require('redis');
const client = redis.createClient();
client.get("key", (err, data) => {
if (data) return console.log(data);
// fetch from DB and cache it
});
18. How would you architect a scalable Node.js application?
Key components:
- Load balancer
- Multiple Node.js instances (clustering)
- Microservices architecture
- Database scaling (replication/sharding)
- Caching layer (Redis)
- Queue system for background jobs
High-level flow:
Client → Load Balancer → Node servers → Cache/DB → Response
19. What design patterns are commonly used in Node.js?
Common patterns:
- Singleton → single instance
- Factory → object creation
- Observer → event-based (EventEmitter)
- Middleware pattern → request processing
- Module pattern → encapsulation
20. What is the Reactor Pattern?
The Reactor Pattern is the design pattern used by Node.js to handle I/O operations.
Concept:
- Single thread listens for events
- Delegates tasks
- Executes callbacks when ready
Steps:
- Event arrives
- Event loop detects it
- Handler (callback) is executed
Example concept:
setTimeout(() => {
console.log("Handled asynchronously");
}, 1000);
Key idea:
- Efficient handling of multiple I/O operations without blocking
21. What is CQRS?
CQRS (Command Query Responsibility Segregation) is a design pattern that separates read and write operations.
Concept:
- Command → modifies data (create, update, delete)
- Query → reads data
Why use it:
- Improves scalability
- Optimizes read/write performance separately
- Simplifies complex systems
Example:
// Command
app.post('/user', createUser);
// Query
app.get('/user/:id', getUser);
22. What is the Circuit Breaker pattern?
The Circuit Breaker pattern prevents repeated calls to a failing service.
States:
- Closed → normal operation
- Open → calls blocked
- Half-open → testing recovery
Purpose:
- Prevent system overload
- Improve fault tolerance
Example (concept):
if (serviceDown) {
return "Fallback response";
}
23. How do you design idempotent APIs?
An API is idempotent if multiple identical requests produce the same result.
Techniques:
- Use unique request IDs
- Avoid duplicate operations
- Use PUT instead of POST when possible
Example:
app.put('/user/1', updateUser);
Calling it multiple times gives the same result.
24. How do you implement API versioning?
Methods:
- URL versioning
/api/v1/users
/api/v2/users
- Header versioning
Accept: application/vnd.myapi.v1+json
- Query parameter
/users?version=1
Best practice:
Use URL versioning for simplicity.
25. What are microservices?
Microservices architecture breaks an application into small, independent services.
Characteristics:
- Each service handles a specific function
- Independently deployable
- Communicate via APIs
26. Why is Node.js suitable for microservices?
Node.js is suitable because:
- Lightweight and fast
- Non-blocking I/O
- Easy to build APIs
- Works well with JSON
- Large ecosystem
27. How do services communicate in microservices?
Methods:
- HTTP/REST APIs
- Message queues (async)
- gRPC
Example:
axios.get('http://user-service/users');
28. What is eventual consistency?
Eventual consistency means that data will become consistent over time, not immediately.
Used in:
- Distributed systems
- Microservices
Example:
- Order placed → inventory updates later
29. How do you implement message queues?
Message queues allow asynchronous communication between services.
Tools:
- RabbitMQ
- Kafka
Example (RabbitMQ concept):
channel.sendToQueue('task_queue', Buffer.from('message'));
Flow:
Producer → Queue → Consumer
31. Difference between Kafka and RabbitMQ (Node.js perspective)
Apache Kafka vs RabbitMQ
| Feature | Kafka | RabbitMQ |
|---|---|---|
| Type | Streaming platform | Message broker |
| Use case | High-throughput data streaming | Task queues |
| Persistence | Strong | Optional |
| Ordering | Partition-based | Queue-based |
| Performance | Very high | Moderate |
| Complexity | Higher | Easier |
Summary:
- Kafka → large-scale streaming systems
- RabbitMQ → simple message queuing
32. How do you handle retries and dead-letter queues?
Retries and dead-letter queues (DLQ) are used to handle failed message processing.
Retry strategy:
- Retry failed messages with delay
- Use exponential backoff
Dead-letter queue:
- Messages that fail repeatedly are moved to DLQ
- Allows debugging without blocking the system
Example (concept):
if (retryCount < 3) {
retryMessage();
} else {
moveToDLQ(message);
}
33. How do you handle distributed transactions?
In distributed systems, traditional transactions are difficult.
Solutions:
- Saga pattern
- Sequence of local transactions
- Rollback using compensating actions
- Event-driven approach
Example:
- Order service → Payment service → Inventory
- If payment fails → cancel order
34. How do you secure a Node.js application end-to-end?
Key practices:
- Use HTTPS (TLS)
- Validate inputs
- Use Helmet for headers
- Implement authentication & authorization
- Use environment variables
- Prevent XSS, CSRF
- Use rate limiting
35. How do you implement authentication and authorization?
Authentication:
- Verify identity (JWT, sessions)
Authorization:
- Check permissions (roles)
Example:
function auth(req, res, next) {
if (!req.user) return res.status(401).send("Unauthorized");
next();
}
function authorize(role) {
return (req, res, next) => {
if (req.user.role !== role) return res.status(403).send("Forbidden");
next();
};
}
36. How do you handle TLS/SSL in Node.js?
Use HTTPS module with certificates.
Example:
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
https.createServer(options, (req, res) => {
res.end("Secure server");
}).listen(443);
37. What is the crypto module used for?
The crypto module is used for:
- Hashing
- Encryption/decryption
- Digital signatures
- Secure random data
Example:
const crypto = require('crypto');
const hash = crypto.createHash('sha256')
.update('data')
.digest('hex');
console.log(hash);
38. How do you prevent resource starvation?
Resource starvation occurs when some tasks never get executed.
Prevention:
- Avoid blocking code
- Limit
process.nextTickusage - Use queues and scheduling
- Prioritize tasks properly
39. What is structured logging?
Structured logging means logging data in a consistent, machine-readable format (like JSON).
Benefits:
- Easier parsing
- Better monitoring
- Integration with tools
Example:
console.log(JSON.stringify({
level: "info",
message: "User logged in",
userId: 1
}));
40. What is distributed tracing?
Distributed tracing tracks a request across multiple services.
Purpose:
- Debug microservices
- Measure latency
Example:
- Request → API → Service → DB
- Trace each step
41. What is OpenTelemetry?
OpenTelemetry is an open-source framework for collecting:
- Metrics
- Logs
- Traces
Benefit:
- Standardized observability
- Works with multiple tools
42. How do you debug production issues?
Methods:
- Logs (structured logging)
- Monitoring tools
- Tracing (OpenTelemetry)
- Heap/CPU profiling
- Reproduce issue locally
43. How do you handle graceful shutdowns?
Graceful shutdown ensures ongoing requests finish before exit.
Example:
process.on('SIGTERM', () => {
server.close(() => {
console.log("Server closed");
});
});
44. How do you set up CI/CD for Node.js?
Steps:
- Code push → Git
- Run tests
- Build app
- Deploy automatically
Tools:
- GitHub Actions
- Jenkins
- GitLab CI
45. How do you deploy a Node.js application?
Options:
- Cloud (AWS, Azure)
- Containers (Docker)
- PaaS (Heroku)
Basic steps:
- Build app
- Install dependencies
- Start server
46. How do you handle zero-downtime deployments?
Techniques:
- Rolling updates
- Blue-green deployment
- Load balancer switching
Benefit:
- No service interruption
47. How do you monitor Node.js applications?
Tools and methods:
- Metrics (CPU, memory)
- Logs
- Alerts
- APM tools (New Relic, Datadog)
Example:
console.log(process.memoryUsage());