Flamegraph Profiling Middleware for Node.js

raw JSON →
1.0.0 verified Thu Apr 23 auth: no javascript

Flamegraph Middleware provides an HTTP interface for on-demand CPU and heap profiling of Node.js applications, visualizing the results as interactive flamegraphs directly in the browser. It is currently at stable version 1.0.0 and designed to be framework-agnostic, working seamlessly with native `http` servers, Express, Fastify, and other HTTP frameworks. Key differentiators include its non-blocking background profiling, dual CPU and heap profiling capabilities, and temporary in-memory storage of profiles with automatic expiration. This tool is invaluable for identifying performance bottlenecks and memory leaks in production or development environments, offering a user-friendly WebGL-powered visualization for deep analysis of execution paths and memory allocation patterns. The package emphasizes ease of integration and real-time insights.

error ERR_REQUIRE_ESM: Must use import to load ES Module:
cause Attempting to `require()` `flamegraph-middleware` in a CommonJS context.
fix
Switch your project to ESM by adding "type": "module" to your package.json and using import { createFlamegraphMiddleware } from 'flamegraph-middleware'.
error Error: Middleware is not a function
cause Incorrectly calling `app.use(flamegraph)` directly when `flamegraph` is the result of `createFlamegraphMiddleware()` (which is a factory).
fix
Ensure you are using the *result* of the factory function. For Express/Fastify, it should be app.use(createFlamegraphMiddleware()) or app.use(flamegraphMiddlewareInstance).
error ReferenceError: require is not defined in ES module scope
cause Using `require()` inside an ES module (where `"type": "module"` is set in `package.json`).
fix
Replace require('module') with import module from 'module' or import { namedExport } from 'module' for all dependencies.
breaking This package is ESM-only and explicitly requires Node.js version 18.0.0 or higher. Attempting to use it with CommonJS `require()` or older Node.js versions will result in runtime errors.
fix Ensure your project is configured for ESM (`"type": "module"` in `package.json`) and you are running Node.js 18+ or higher. Use `import` statements exclusively.
gotcha When integrating with Fastify, the `@fastify/middie` plugin is required to use `flamegraph-middleware` as a standard HTTP middleware. Failure to register `middie` first will prevent the middleware from being properly applied.
fix Register `@fastify/middie` before using `flamegraph-middleware`: `await fastify.register(middie); fastify.use(createFlamegraphMiddleware(...))`
gotcha The default duration for profiling is 10 seconds, and the maximum allowed duration is 60 seconds. Profiles exceeding `maxDuration` via query parameter will be capped, and very long profiles can consume significant CPU and memory resources on the target server.
fix Carefully manage `defaultDuration` and `maxDuration` in production environments. Request profiles with specific durations (e.g., `?duration=5000`) and avoid excessively long profiles.
gotcha Profiles are stored temporarily in memory and automatically expire. If the `maxProfiles` limit is reached, older profiles will be evicted. Profiles also expire after `profileTTL` milliseconds.
fix Adjust `maxProfiles` and `profileTTL` configuration options based on your monitoring needs and available memory. Download or view profiles promptly after completion if long-term storage is required.
npm install flamegraph-middleware
yarn add flamegraph-middleware
pnpm add flamegraph-middleware

Demonstrates integrating `flamegraph-middleware` into an Express application, showing how to configure it, start a CPU/heap profile via HTTP, and access the interactive flamegraph visualizations.

import express from 'express';
import { createFlamegraphMiddleware } from 'flamegraph-middleware';

const app = express();

// Configure and use the flamegraph middleware
// Access profiles at http://localhost:3000/flamegraph
app.use(createFlamegraphMiddleware({
  basePath: '/flamegraph',
  defaultDuration: 10000, // 10 seconds
  maxDuration: 60000,   // Max 1 minute profile
  profileTTL: 300000    // Profiles expire after 5 minutes
}));

app.get('/', (req, res) => {
  res.send('Hello World! Access /flamegraph to start profiling.');
});

app.get('/slow', (req, res) => {
  let sum = 0;
  for (let i = 0; i < 1e7; i++) {
    sum += Math.sqrt(i);
  }
  res.send(`Computed sum: ${sum}. Profile this endpoint with /flamegraph?duration=5000`);
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Express server running at http://localhost:${PORT}`);
  console.log(`Start a profile: http://localhost:${PORT}/flamegraph?duration=5000`);
  console.log(`View results after profiling: http://localhost:${PORT}/flamegraph`);
});