pyroscope-nodejs
Continuous CPU and heap profiling for Node.js apps, exported directly to Grafana Pyroscope.
Repository Health
Technical Analysis
Pyroscope Node.js is Grafana’s official profiling client for Node.js services. It wraps V8’s sample-based profiler (via @datadog/pprof) in a continuous, timer-driven collection loop that periodically snapshots wall-clock and heap profiles and ships them as pprof-encoded data to a Pyroscope server, so teams get an always-on flamegraph history instead of a one-off snapshot taken during an incident.
Beyond the push-based continuous mode, the package ships Express and Fastify middleware that expose standard /debug/pprof/* endpoints for pull-based scraping, dynamic per-request tag labels for slicing flamegraphs by things like tenant or route, and a source-mapper that resolves compiled JavaScript stack frames back to original TypeScript source lines. It is purpose-built as the Node.js SDK for the Grafana Pyroscope profiling backend rather than a general-purpose profiling toolkit.
What You Get
- A single
init()call that reads server address, auth, and sampling config from options or environment variables and starts a continuous profiling loop - Wall-clock and heap profilers built on @datadog/pprof’s native V8 bindings, coordinated through a shared
ContinuousProfilerscheduler - Express and Fastify middleware exposing
/debug/pprof/heapand/debug/pprof/profilefor pull-mode scraping with existing pprof tooling - Dynamic label support (
wrapWithLabels,setLabels) to tag profile samples with request- or tenant-specific metadata for later filtering - A built-in source mapper that translates compiled JS stack frames back to original TypeScript file/line numbers in the resulting flamegraphs
Common Use Cases
- Running always-on CPU/heap profiling in production Node.js services to catch regressions before they page anyone
- Correlating performance hotspots with business dimensions (tenant, route, job type) via per-request profile labels
- Exposing pprof-compatible debug endpoints on an Express or Fastify service for ad-hoc profiling with standard pprof tooling
- Feeding continuous profiling data into Grafana alongside existing metrics and traces for full observability correlation
Under The Hood
Architecture
The package is organized into three layers: profilers/ wraps @datadog/pprof’s native V8 profiler behind a small Profiler<TStartArgs> interface, with ContinuousProfiler (src/profilers/continuous-profiler.ts) adding a timer-driven schedule/export loop shared by both the wall and heap profilers inside PyroscopeProfiler. middleware/ (express.ts, fastify.ts) offers a pull-mode path that drives the same Profiler interface directly on an HTTP request rather than through the continuous scheduler, trading some code reuse for a simpler synchronous request/response flow. pyroscope-api-exporter.ts implements a ProfileExporter that gzips and POSTs pprof-encoded buffers to a /ingest endpoint with bearer or basic auth and tenant headers, while sourcemapper.ts post-processes profiles to resolve bundled JS frames back to original source locations. The top-level index.ts composes these pieces behind a small init/start/stop public API, so most of the coordination complexity is hidden from consumers.
Tech Stack
Written in TypeScript and built to dual ESM/CJS output via separate tsconfig.cjs.json/tsconfig.esm.json configs and custom build scripts in tools/. Core dependency is @datadog/pprof for native V8 profiling bindings, alongside pprof-format for protobuf-based pprof encoding, debug for namespaced logging, and source-map for stack resolution. Express and Fastify are optional peer dependencies gated behind peerDependenciesMeta.optional, so the middleware is opt-in and doesn’t force either framework on consumers. The project uses Yarn 4 (Berry) with pinned resolutions for several transitive dependencies, Husky for pre-commit hooks, and ships releases through a GitHub Actions workflow using release-please and npm’s OIDC trusted publishing rather than a static npm token.
Code Quality
Tests use Node’s built-in node:test runner rather than a separate framework, and several suites (express.test.ts, fastify.test.ts, profiler.test.ts) spin up a real Express server to assert actual HTTP ingest behavior end-to-end instead of mocking the network layer. Types are used throughout, including generic Profiler<TStartArgs> and ContinuousProfilerInput<TStartArgs> interfaces that keep the wall and heap profiler implementations structurally consistent. ESLint and Prettier are configured with lint-staged via Husky, and a dedicated GitHub Actions workflow runs the test suite on every change. The network export path wraps upload failures in try/catch and logs rather than throwing, favoring resilience of the host application over guaranteed delivery of any single profile.
API Design
The public surface is intentionally small: init(config) plus start/stop cover the common case, with configuration resolvable from environment variables to minimize required boilerplate for container-based deployments. Dynamic per-request labeling (wrapWithLabels, getLabels/setLabels) is a differentiated capability that lets consumers correlate flamegraph data with application-level context rather than just wall-clock time. Deprecated aliases (startCpuProfiling, getWallLabels) are kept alongside their replacements for backward compatibility, and the pull-mode middleware reuses standard /debug/pprof/* paths so existing pprof-based tooling works without modification.
Used by 3 apps in this directory
OneUptime
Monitoring
The complete open-source observability platform that replaces PagerDuty, Datadog, Sentry, and StatusPage with a single self-hostable system.
PostHog
Analytics · Monitoring · Developer Tools
The all-in-one open source product platform combining analytics, session replay, feature flags, error tracking, AI observability, and a built-in data warehouse in a single self-hostable stack.
Pyroscope
Monitoring · Devops · Developer Tools
An open-source, horizontally scalable continuous profiling platform that pinpoints CPU, memory, and I/O bottlenecks down to the exact line of code, built by Grafana Labs alongside Loki, Tempo, and Mimir.