---
name: v8-profiling
description: >-
  V8 profiling quick reference for JavaScript/TypeScript projects. Use when the user
  mentions "profile", "cpu profile", "heap snapshot", "heap profile", "v8 profiler",
  "clinic", "flame graph", "memory profile", "allocation tracking", "--cpu-prof",
  "--heap-prof", or wants to understand V8 profiling output.
allowed-tools: "Read, Bash"
---

# V8 Profiling Quick Reference

## CPU Profiling

### Node.js built-in (recommended)

```bash
# Generate CPU profile (outputs .cpuprofile JSON):
node --cpu-prof --cpu-prof-dir=.codeflash/ app.js

# With specific test:
node --cpu-prof --cpu-prof-dir=.codeflash/ node_modules/.bin/vitest run tests/target.test.ts

# Process V8 tick log (alternative, text output):
node --prof app.js
node --prof-process isolate-*.log > profile.txt
```

### clinic.js flame (visual)

```bash
npx clinic flame -- node app.js
```

### V8 deoptimization tracing

```bash
# Trace deoptimizations:
node --trace-deopt app.js 2>&1 | grep -i "deopt"

# Trace inline cache state (hidden class transitions):
node --trace-ic app.js 2>&1 | head -200

# Trace both optimization and deoptimization:
node --trace-opt --trace-deopt app.js 2>&1 | grep -E "optimiz|deopt"
```

### Chrome DevTools

```bash
# Start with inspector:
node --inspect app.js
# Open chrome://inspect, attach, go to Performance tab, record
```

## Memory Profiling

### Heap snapshots

```javascript
const v8 = require('node:v8');

// Take a snapshot (writes .heapsnapshot file):
v8.writeHeapSnapshot();

// For leak detection: take before/after snapshots, compare in Chrome DevTools
// IMPORTANT: force GC before snapshot for accurate readings
// Run with: node --expose-gc app.js
global.gc();
const snap1 = v8.writeHeapSnapshot();
// ... run suspected leaking code ...
global.gc();
const snap2 = v8.writeHeapSnapshot();
```

### Heap allocation profiling

```bash
# Allocation sampling over time:
node --heap-prof app.js
# Outputs .heapprofile — open in Chrome DevTools Memory tab
```

### Quick memory check

```javascript
const mem = process.memoryUsage();
console.log({
  rss: `${(mem.rss / 1024 / 1024).toFixed(1)} MB`,
  heapUsed: `${(mem.heapUsed / 1024 / 1024).toFixed(1)} MB`,
  heapTotal: `${(mem.heapTotal / 1024 / 1024).toFixed(1)} MB`,
  external: `${(mem.external / 1024 / 1024).toFixed(1)} MB`,
});
```

### Per-stage memory profiling

```javascript
// Run with: node --expose-gc script.js
function snap(label) {
  global.gc?.();
  return { label, heapUsed: process.memoryUsage().heapUsed };
}

const stages = [snap('start')];
await stageA();
stages.push(snap('after stageA'));
await stageB();
stages.push(snap('after stageB'));

for (let i = 1; i < stages.length; i++) {
  const delta = (stages[i].heapUsed - stages[i-1].heapUsed) / 1024 / 1024;
  console.log(`${stages[i].label}: ${delta > 0 ? '+' : ''}${delta.toFixed(1)} MiB`);
}
```

### clinic.js heapprofiler

```bash
npx clinic heapprofiler -- node app.js
```

## Event Loop / Async Profiling

### Event loop delay monitoring

```javascript
const { monitorEventLoopDelay } = require('node:perf_hooks');
const h = monitorEventLoopDelay({ resolution: 20 });
h.enable();
setTimeout(() => {
  console.log(`p50: ${(h.percentile(50) / 1e6).toFixed(1)}ms`);
  console.log(`p99: ${(h.percentile(99) / 1e6).toFixed(1)}ms`);
  console.log(`max: ${(h.max / 1e6).toFixed(1)}ms`);
  h.disable();
}, 5000);
```

### clinic.js bubbleprof

```bash
npx clinic bubbleprof -- node app.js
```

### clinic.js doctor (overall diagnosis)

```bash
npx clinic doctor -- node app.js
```

## Benchmarking

### mitata (recommended for A/B comparison)

```javascript
import { bench, run, summary } from 'mitata';

summary(() => {
  bench('current', () => { /* original code */ });
  bench('optimized', () => { /* new code */ });
});

await run(); // or run({ format: 'json' }) for machine-readable
```

### Quick timing

```javascript
const { performance } = require('node:perf_hooks');

const WARMUP = 1000;
const N = 10000;

// Warmup (let V8 JIT optimize)
for (let i = 0; i < WARMUP; i++) targetFunction(data);

const start = performance.now();
for (let i = 0; i < N; i++) targetFunction(data);
const elapsed = performance.now() - start;
console.log(`${elapsed.toFixed(2)}ms for ${N} iterations (${(elapsed/N).toFixed(4)}ms/op)`);
```

## Key V8 Flags Reference

| Flag | Purpose |
|------|---------|
| `--cpu-prof` | Generate .cpuprofile (CPU sampling) |
| `--cpu-prof-dir=<dir>` | Output directory for CPU profiles |
| `--heap-prof` | Generate .heapprofile (allocation sampling) |
| `--expose-gc` | Allow `global.gc()` for forced GC |
| `--max-old-space-size=<MB>` | Set V8 old space limit |
| `--prof` | Generate V8 tick log |
| `--trace-deopt` | Log deoptimizations |
| `--trace-opt` | Log optimizations |
| `--trace-ic` | Log inline cache state changes |
| `--inspect` | Enable Chrome DevTools debugger |
| `--heapsnapshot-signal=SIGUSR2` | Take heap snapshot on signal |
