npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

loadometer

v0.2.8

Published

Profile how long your app spends loading modules (require and import, Node and Bun) as folded stacks you can render into a flame graph.

Readme

loadometer

See where your app spends time loading modules, as a flame graph.

loadometer times every module your app loads — require() and import, JavaScript and TypeScript — and writes the result as folded stacks (import;chain milliseconds), the format flame-graph tools understand.

Install

npm install --save-dev loadometer

Usage

Run your app with loadometer as a preload — no code changes:

node --import loadometer/register app.js      # Node
bun  --preload loadometer/register app.js     # Bun

This is the recommended way everywhere. The preload hooks the module loader and times each module's load and evaluation, covering require() and import, in both JavaScript and TypeScript.

Run it: print to the console

By default the folded stacks are printed to stdout:

node --import loadometer/register app.js
./app.js 42
./app.js;express 31
./app.js;express;body-parser 8

Each line is an import chain and how many milliseconds that load took.

Run it: write to a file

Set LOADOMETER_OUT_FILE to write the folded stacks to a file instead:

LOADOMETER_OUT_FILE=imports.folded node --import loadometer/register app.js

Visualize it on the web

Open speedscope.app and drag your imports.folded file onto the page — it renders an interactive flame graph, no install required.

Prefer an SVG? Any folded-stack renderer works:

npx inferno imports.folded > imports.svg
# or Brendan Gregg's script:
flamegraph.pl imports.folded > imports.svg

How it works

loadometer measures the wall-clock time each module takes to load, then writes it as folded stacks. It uses two mechanisms, depending on how a module is loaded:

CommonJS (require). It wraps Module.prototype.require and measures with performance.now() around the original call. Because require() synchronously reads, compiles, and executes the module — and everything that module requires in turn — the time is inclusive: a module's number includes its children.

ESM (import), via the preload. Native imports never call require, and a module's body runs after its dependencies are loaded, so there's no single call to wrap. Instead the loader hooks do two things per module:

  1. Time the load step — reading the file and transpiling it (e.g. stripping TypeScript types).

  2. Rewrite the module's source to insert timestamps around its body, timing its evaluation (the top-level code actually running). The resolve step records each module's importer, which is how the a;b;c import chain is rebuilt.

    The reported number is load + evaluation for that module.

What a line means. Output is one line per module in folded-stack form:

express;body-parser;bytes 3

reads as "loading bytes, imported by body-parser, imported by express, took 3 ms." Flame-graph tools size each box by summing its children, turning these lines into the familiar width-is-time picture.

It's wall-clock time, not CPU time, so it includes disk I/O and any waiting (such as top-level await). A module that's already cached loads in ~0 ms — the work only happens the first time it's pulled in.

TypeScript

Works out of the box. The preload instruments TypeScript source directly, so it covers Node's built-in type stripping, tsx / ts-node, and Bun's native TS — no separate build step.

Coverage, and the require() workaround

| Runtime | --import / --preload …/register (recommended) | require('loadometer') | |---------|:-------------------------------------------------:|:-----------------------:| | Node | CommonJS + ESM | CommonJS | | Bun | ESM | CommonJS |

The preload is the way to go everywhere — with one exception: on Bun, require()'d CommonJS dependencies bypass Bun's loader plugin, so the preload sees only ESM there.

For a CommonJS app on Bun, use the in-file import as a workaround — drop this at the very top of your entry, before anything else (Bun routes require through Module.prototype.require, so this captures the loads below it):

require('loadometer'); // must be first
require('./app');

Examples

Runnable examples live in examples/ — quick scripts, self-contained repos for every Node / Bun × JS / TS × CommonJS / ESM combination, and a long-running demo server. Run any of them with npm:

npm run example:1            # console output
npm run example:2            # writes imports.folded

npm run example:node-js-esm  # Node + JS + native ESM (preload)
npm run example:bun-ts-esm   # Bun  + TS + native ESM (preload)
npm run example:node-ts-cjs  # Node + TS + CommonJS
# …every runtime × language × module system — 8 in total

npm run example:server       # long-running server: hit /load?pkg=…, then Ctrl+C
npm run examples             # run the whole matrix at once

See examples/README.md for the full matrix. (Bun scripts need bun on your PATH.)

Notes

  • What the numbers mean. The preload times each module's load + its own evaluation; the require('loadometer') workaround times each load inclusively (the module and everything it pulls in). Both render fine as a flame graph.