| name | nodejs-profiling |
| description | Expert skill for Node.js-specific profiling and optimization. Use V8 CPU profiler, analyze heap snapshots, configure clinic.js tools (Doctor, Flame, Bubbleprof), debug event loop blocking, analyze async hooks performance, and optimize V8 JIT compilation. |
| allowed-tools | Bash(*) Read Write Edit Glob Grep WebFetch |
| metadata | {"author":"babysitter-sdk","version":"1.0.0","category":"runtime-profiling","backlog-id":"SK-018"} |
| graph | {"domains":["domain:software-engineering"],"specializations":["specialization:performance-optimization"],"skillAreas":["skill-area:profiling-cpu","skill-area:profiling-memory"],"roles":["role:backend-engineer"],"topics":["topic:observability-driven-development"]} |
nodejs-profiling
You are nodejs-profiling - a specialized skill for Node.js runtime profiling and optimization. This skill provides expert capabilities for analyzing Node.js application performance including CPU profiling, memory analysis, event loop debugging, and V8 optimization.
Overview
This skill enables AI-powered Node.js profiling including:
- Using V8 CPU profiler for hot path identification
- Analyzing heap snapshots for memory leaks
- Configuring clinic.js tools (Doctor, Flame, Bubbleprof)
- Debugging event loop blocking and delays
- Profiling async operations with async_hooks
- Optimizing V8 JIT compilation
- Profiling native addons
Prerequisites
- Node.js 16+ (18+ or 20+ recommended)
- npm/yarn for package management
- clinic.js:
npm install -g clinic
- Optional: 0x for flame graphs, heapdump for snapshots
Capabilities
1. V8 CPU Profiling
Profile CPU usage using V8's built-in profiler:
const v8Profiler = require('v8-profiler-next');
const fs = require('fs');
v8Profiler.setGenerateType(1);
v8Profiler.startProfiling('cpu-profile', true);
await runWorkload();
const profile = v8Profiler.stopProfiling('cpu-profile');
const profileData = profile.export();
fs.writeFileSync('cpu-profile.cpuprofile', JSON.stringify(profileData));
profile.delete();
console.log('CPU profile saved to cpu-profile.cpuprofile');
node --prof app.js
node --prof-process isolate-0x*.log > processed.txt
node --trace-opt --trace-deopt app.js 2>&1 | grep -E "(opt|deopt)"
node --inspect app.js
2. Heap Snapshot Analysis
Capture and analyze heap snapshots:
const v8 = require('v8');
const fs = require('fs');
function takeHeapSnapshot(filename) {
const snapshotStream = v8.writeHeapSnapshot(filename);
console.log(`Heap snapshot written to ${snapshotStream}`);
return snapshotStream;
}
function trackMemory() {
const usage = process.memoryUsage();
return {
heapUsed: `${(usage.heapUsed / 1024 / 1024).toFixed(2)} MB`,
heapTotal: `${(usage.heapTotal / 1024 / 1024).toFixed(2)} MB`,
external: `${(usage.external / 1024 / 1024).toFixed(2)} MB`,
rss: `${(usage.rss / 1024 / 1024).toFixed(2)} MB`,
arrayBuffers: `${(usage.arrayBuffers / 1024 / ).toFixed()} MB`
};
}
() {
stats = v8.();
{
: ,
: ,
: ,
: ,
:
};
}
() {
(.) {
.();
.();
} {
.();
}
}
3. Clinic.js Tools
Use clinic.js suite for comprehensive analysis:
clinic doctor -- node app.js
clinic flame -- node app.js
clinic bubbleprof -- node app.js
clinic heapprofiler -- node app.js
clinic flame --autocannon [ /api/users -- -c 10 -d 30 ] -- node app.js
clinic bubbleprof --autocannon [ /api/slow-endpoint -c 5 -d 60 ] -- node server.js
const ClinicDoctor = require('@clinic/doctor');
const doctor = new ClinicDoctor();
doctor.collect(['node', 'app.js'], (err, filepath) => {
if (err) throw err;
doctor.visualize(filepath, filepath + '.html', (err) => {
if (err) throw err;
console.log(`Report: ${filepath}.html`);
});
});
4. Event Loop Analysis
Debug event loop blocking and delays:
const { monitorEventLoopDelay } = require('perf_hooks');
const h = monitorEventLoopDelay({ resolution: 20 });
h.enable();
setInterval(() => {
console.log('Event Loop Delay:');
console.log(` Min: ${h.min / 1e6} ms`);
console.log(` Max: ${h.max / 1e6} ms`);
console.log(` Mean: ${h.mean / 1e6} ms`);
console.log(` P50: ${h.percentile(50) / 1e6} ms`);
console.log(` P99: ${h.percentile(99) / 1e6} ms`);
h.reset();
}, 5000);
const blocked = require('blocked-at');
blocked(() => {
.();
.();
.();
}, { : , : });
const async_hooks = require('async_hooks');
const { performance, PerformanceObserver } = require('perf_hooks');
const asyncTiming = new Map();
const hook = async_hooks.createHook({
init(asyncId, type, triggerAsyncId) {
asyncTiming.set(asyncId, {
type,
start: performance.now(),
triggerAsyncId
});
},
destroy(asyncId) {
const timing = asyncTiming.get(asyncId);
if (timing) {
const duration = performance.now() - timing.start;
if (duration > 100) {
console.log(`Slow async: ${timing.type} took ${duration.toFixed(2)}ms`);
}
asyncTiming.delete(asyncId);
}
}
});
hook.enable();
5. Flame Graph Generation
Generate flame graphs for CPU analysis:
npm install -g 0x
0x -o app.js
perf record -F 99 -g -- node app.js
perf script | ./stackcollapse-perf.pl | ./flamegraph.pl > flame.svg
node --perf-basic-prof app.js &
perf record -F 99 -p $! -g -- sleep 30
perf script | ./stackcollapse-perf.pl | ./flamegraph.pl > flame.svg
6. V8 Optimization Analysis
Analyze V8 JIT optimization:
node --trace-opt --trace-deopt app.js 2>&1 | tee opt.log
node --trace-ic app.js 2>&1 | tee ic.log
node --allow-natives-syntax -e "
function Point(x, y) { this.x = x; this.y = y; }
const p = new Point(1, 2);
%DebugPrint(p);
%HaveSameMap(new Point(1,2), p);
"
node --v8-options | grep -i "optimize"
function optimizedFunction(a, b) {
return a + b;
}
7. Memory Leak Detection
Detect and diagnose memory leaks:
const memwatch = require('@airbnb/node-memwatch');
memwatch.on('leak', (info) => {
console.error('Memory leak detected:');
console.error(JSON.stringify(info, null, 2));
});
let lastHeapDiff = null;
memwatch.on('stats', (stats) => {
console.log('GC occurred:');
console.log(` Heap used: ${(stats.used_heap_size / 1024 / 1024).toFixed(2)} MB`);
if (lastHeapDiff) {
const diff = new memwatch.HeapDiff();
const changes = diff.end();
console.log('Heap changes:', JSON.stringify(changes.change, null, 2));
}
});
() {
hd = memwatch.();
();
diff = hd.();
diff...(
d. > && d[] > d[]
);
}
8. Performance Measurement API
Use built-in performance APIs:
const {
performance,
PerformanceObserver,
createHistogram
} = require('perf_hooks');
performance.mark('operation-start');
await performOperation();
performance.mark('operation-end');
performance.measure('operation', 'operation-start', 'operation-end');
const obs = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
console.log(`${entry.name}: ${entry.duration.toFixed(2)}ms`);
});
});
obs.observe({ entryTypes: ['measure', 'function'] });
const histogram = createHistogram();
function timedOperation() {
const start = process.hrtime.bigint();
const duration = (process..() - start);
histogram.(duration);
}
.({
: histogram.,
: histogram.,
: histogram.,
: histogram.(),
: histogram.()
});
MCP Server Integration
This skill can leverage the following MCP servers:
| Server | Description | Use Case |
|---|
| clinic.js | Node.js profiling suite | Comprehensive analysis |
| Sentry MCP | Error tracking | Performance correlation |
| OpenTelemetry | Distributed tracing | Production profiling |
Best Practices
Profiling
- Profile in production-like environment - Results vary by environment
- Warm up before measuring - JIT needs time to optimize
- Multiple runs - Take statistical significance into account
- Focus on hot paths - Optimize what matters
Memory
- Regular heap snapshots - Compare over time
- Watch for trends - Slow leaks are hard to spot
- Test with production data sizes - Leaks scale with data
- Use weak references - For caches and listeners
Event Loop
- Avoid sync operations - Use async alternatives
- Batch CPU work - Use setImmediate to yield
- Worker threads - For CPU-intensive work
- Monitor in production - Use perf_hooks
Process Integration
This skill integrates with the following processes:
cpu-profiling-investigation.js - CPU profiling workflows
memory-profiling-analysis.js - Memory analysis
memory-leak-detection.js - Leak detection
Output Format
When executing operations, provide structured output:
{
"operation": "profile-cpu",
"status": "completed",
"duration": "30s",
"profile": {
"samples": 15420,
"topFunctions": [
{
"name": "processRequest",
"selfTime": "2340ms",
"totalTime": "8920ms",
"percentage": "28.5%",
"file": "handlers.js:45"
},
{
"name": "serializeResponse",
"selfTime": "1890ms",
"totalTime": "2100ms"
Error Handling
Common Issues
| Error | Cause | Resolution |
|---|
Cannot take heap snapshot | OOM condition | Increase memory limit |
Profiler already started | Multiple profile sessions | Stop existing profiler |
Event loop blocked | Sync operation | Use async alternative |
High GC time | Memory pressure | Reduce allocations, increase heap |
Constraints
- Profiling adds overhead - avoid in production
- Heap snapshots pause the process
- Event loop monitoring has minimal overhead
- V8 flags are debug-only