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

importree

v1.0.1

Published

Build import dependency trees for TypeScript and JavaScript files. Fast, zero-dependency static analysis for dependency detection and cache invalidation.

Readme

importree

npm version npm downloads bundle size license

Build import dependency trees for TypeScript and JavaScript files. Fast, zero-dependency static analysis for dependency detection and cache invalidation.

When a file changes, you need to know what else is affected. importree builds the full import dependency tree for any TypeScript or JavaScript entry point — with zero dependencies and zero AST overhead.

Built for CI pipelines, build tools, monorepo task runners, and test selectors.

Website · GitHub · npm

Highlights

  • Zero dependencies — Built entirely on Node.js built-ins. No native binaries, no WASM.
  • Fast scanning — Regex-based import extraction with concurrent async file traversal. No AST parsing overhead.
  • Path alias support — Resolve @/components, ~/utils, or any custom alias with longest-prefix matching and automatic extension probing.
  • Cache invalidation — Pre-computed reverse dependency graph answers "what needs rebuilding?" instantly.
  • Dual output — Ships both ESM and CJS with full TypeScript declarations.

Benchmarks

Measured with Vitest bench on Node.js v22. Results vary by hardware.

Comparison with alternatives

Each tool brings different strengths — dependency-tree offers robust AST-based analysis via detective, madge supports multiple languages and provides circular dependency detection with visualization. importree trades those features for raw speed through regex-based extraction.

| Scenario | importree | dependency-tree | madge | Manual glob+regex | ts.createProgram | |----------|-----------|-----------------|-------|-------------------|------------------| | Small (10 files) | 0.4 ms | 3.1 ms | 3.7 ms | 0.6 ms | 49.9 ms | | Medium (100 files) | 2.1 ms | 14.3 ms | 15.1 ms | 5.2 ms | 48.4 ms | | Large (500 files) | 12.7 ms | 44.4 ms | 43.3 ms | 26.5 ms | 50.9 ms |

Full tree build

| Project size | Mean time | Throughput | |-------------|-----------|------------| | 10 files | 0.4 ms | ~2,548 ops/s | | 100 files | 2.5 ms | ~406 ops/s | | 500 files | 12.1 ms | ~83 ops/s | | 1,000 files | 26.4 ms | ~38 ops/s |

Scanner throughput

| Operation | Throughput | |-----------|-----------| | scanImports (3 imports) | ~661K ops/s | | scanImports (50 imports) | ~41K ops/s | | stripComments (1,000 lines) | ~2,497 ops/s |

Run pnpm bench:run to reproduce locally.

Install

npm install importree

Requires Node.js >= 18.

Quick Start

Build the tree

import { importree } from 'importree';

const tree = await importree('./src/index.ts', {
  aliases: { '@': './src' },
});

console.log(tree.files);
// ['/abs/src/index.ts', '/abs/src/app.ts', ...]

console.log(tree.externals);
// ['react', 'lodash', 'node:path']

console.log(tree.graph);
// { '/abs/src/index.ts': ['/abs/src/app.ts', ...] }

Find affected files

import { importree, getAffectedFiles } from 'importree';

const tree = await importree('./src/index.ts');

// When utils.ts changes, what needs rebuilding?
const affected = getAffectedFiles(tree, './src/utils.ts');

console.log(affected);
// ['/abs/src/app.ts', '/abs/src/index.ts']
// ^ every file that transitively depends on utils.ts

API

importree(entry, options?)

Recursively resolves all static imports, dynamic imports, require() calls, and re-exports starting from the entry file. Returns the full dependency graph.

importree(entry: string, options?: ImportreeOptions): Promise<ImportTree>

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | entry | string | Yes | Path to the entry file (resolved against cwd) | | options | ImportreeOptions | No | Configuration for resolution behavior |

ImportreeOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | rootDir | string | process.cwd() | Root directory for resolving relative alias paths | | aliases | Record<string, string> | {} | Path alias mappings (e.g., { '@': './src' }) | | extensions | string[] | ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'] | File extensions to try when resolving extensionless imports |

Returns

Promise<ImportTree> — the resolved dependency tree.


getAffectedFiles(tree, changedFile)

BFS traversal of the reverse dependency graph. Returns all files that transitively depend on the changed file — sorted, deterministic, and without the changed file itself.

getAffectedFiles(tree: ImportTree, changedFile: string): string[]

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | tree | ImportTree | Yes | A tree previously returned by importree() | | changedFile | string | Yes | Path to the file that changed (resolved to absolute) |

Returns

string[] — sorted absolute paths of all files that transitively depend on the changed file. The changed file itself is excluded. Returns an empty array if the file is not in the graph.


ImportTree

The result object returned by importree().

| Field | Type | Description | |-------|------|-------------| | entrypoint | string | Absolute path of the entry file | | files | string[] | Sorted absolute paths of all local files in the dependency tree | | externals | string[] | Sorted unique bare import specifiers — packages like react, lodash, node:fs | | graph | Record<string, string[]> | Forward adjacency list. Each file maps to its direct local imports. | | reverseGraph | Record<string, string[]> | Reverse adjacency list. Each file maps to files that import it. |

What gets detected

importree extracts specifiers from all standard import patterns:

  • Static imports — import { foo } from './bar'
  • Default imports — import foo from './bar'
  • Namespace imports — import * as foo from './bar'
  • Side-effect imports — import './bar'
  • Type imports — import type { Foo } from './bar'
  • Dynamic imports — import('./bar')
  • CommonJS require — require('./bar')
  • Re-exports — export { foo } from './bar', export * from './bar'

Imports inside comments and string literals are ignored.

Circular dependencies are handled — each file is visited once.

Resolution

  1. Relative imports (./ or ../) resolve against the importing file's directory.
  2. Alias imports match against the configured aliases using longest-prefix matching, then resolve as relative paths from rootDir.
  3. Bare specifiers (e.g., react, @scope/pkg, node:fs) are classified as external and collected in externals.

For each resolved path, importree probes in order:

  1. Exact path
  2. Path + each extension (.ts, .tsx, .js, .jsx, .mjs, .cjs)
  3. Path as directory + index + each extension

License

ISC — Alex Grozav