fdir
The fastest directory crawler and globbing library for Node.js, built around a chainable builder API with optional picomatch-powered glob support.
Repository Health
Technical Analysis
fdir is a directory-crawling and globbing library for Node.js designed from the ground up for raw throughput — it can walk a directory tree containing one million files in under a second. Rather than exposing a single monolithic function, fdir uses an expressive Builder pattern (new fdir().withFullPaths().crawl(path)) that lets consumers opt into exactly the behavior they need — full paths, relative paths, symlink resolution, depth limits, file/directory filtering, and glob matching — without paying for features they don’t use.
Under the hood, fdir builds its walking, filtering, and path-joining functions conditionally based on which builder options were set, so the JavaScript engine can inline the resulting tiny functions instead of branching on every file it visits. It ships with zero required dependencies (picomatch is an optional peer dependency, only needed for glob matching), works in synchronous, Promise-based, and callback-based modes, and is used in production by projects including Rollup’s plugin suite, Pulumi, dotenvx, and MDN’s Yari.
What You Get
- A chainable
BuilderAPI (new fdir().withXyz().crawl(path)) for composing crawl behavior declaratively - Synchronous (
.sync()), Promise-based (.withPromise()), and callback-based crawling modes - Optional glob matching via the
picomatchpeer dependency, with compiled matchers cached per pattern set - Fine-grained control over output shape: full paths, relative paths, directories-only, grouped-by-directory, or counts-only
- Symlink resolution, max-depth limits, max-file limits, and
AbortSignalsupport for cancellable crawls
Common Use Cases
- Build tools and bundlers (e.g. Rollup plugins) enumerating source files to process
- CLI tools and linters that need to glob-match files across large repositories quickly
- Static site generators and documentation tools (e.g. MDN’s Yari) walking content directories
- Package managers and dependency tools scanning
node_modulestrees for manifests
Under The Hood
Architecture
fdir separates its public API (src/builder/index.ts’s Builder class plus api-builder.ts) from its execution core (src/api/walker.ts’s Walker class), with the walker composed from a set of small, independently swappable functions in src/api/functions/ (join-path, push-directory, push-file, get-array, group-files, resolve-symlink, walk-directory, invoke-callback) that are selected and bound once per Walker construction based on the active Options object, then invoked directly inside the hot per-entry loop in walk(); a Queue (src/api/queue.ts) tracks in-flight async directory reads via a counter so the walk only invokes its result callback once every recursive fs.readdir call has resolved, and an Aborter (src/api/aborter.ts) provides a shared abort flag checked at the top of each walk() invocation. Because the “conditional function” strategy pushes option-branching to construction time rather than per-file, changing the core Options shape (in src/types.ts) is the one change that ripples through nearly every function builder in src/api/functions/.
Tech Stack
fdir is written in TypeScript (strict mode, ESNext target) and builds dual ESM/CJS bundles via tsdown, targeting Node >=12, with zero required runtime dependencies — its only dependency-like relationship is an optional peer dependency on picomatch for glob support, loaded lazily via require.resolve with a try/catch fallback so its absence never causes a hard failure. Tests run on Vitest with @vitest/coverage-v8 for coverage and mock-fs for filesystem fixtures, formatting is enforced via Prettier, and an extensive benchmarks suite (using benny, ts-node, and a long list of competing crawler/glob libraries as devDependencies, including pinned historical versions of fdir itself) tracks performance regressions across releases.
Code Quality
Two test files exercise the public Builder/APIBuilder surface plus a dedicated symlink-resolution suite, backed by mock-fs fixtures, with coverage tracked via @vitest/coverage-v8 and explicit c8 ignore annotations marking deliberately-untested defensive branches. The codebase is fully typed under strict: true TypeScript, uses consistent naming and small single-responsibility modules (one file per builder function), and CI runs tests and the build on every push. No typed error classes are used — filesystem errors pass through largely as-is and are suppressed by default, a documented, deliberate default rather than an oversight.
API Design
The chainable Builder API is fdir’s main ergonomic decision — a call like new fdir().withFullPaths().withMaxDepth(2).crawl(path).sync() reads as a declarative configuration pipeline rather than a single options object, method names map directly to documented behavior, and the same builder supports three execution modes without re-specifying options. Getting started requires zero configuration, and glob support is opt-in via a single .glob() call rather than a separate API surface, though the peer-dependency-based picomatch wiring is a minor discoverability rough edge for a caller who forgets to install it.
Used by 5 apps in this directory
Bun
Developer Tools
An all-in-one JavaScript and TypeScript toolkit — one Rust-and-JavaScriptCore binary that replaces Node.js, npm, a bundler, and a test runner with faster equivalents.
Continue
Developer Tools · AI Development · AI Code Assistants
Open-source coding agent for VS Code, JetBrains, and CLI with support for 30+ LLM providers.
likec4
Developer Tools · Devops
Define your software architecture as code and get always up-to-date, interactive C4 diagrams generated automatically from a DSL.
medusa
Ecommerce
The most flexible open-source commerce platform — build B2C, B2B, and marketplace applications with modular, composable commerce primitives.
Notesnook
Note Taking · File Storage · Security
End-to-end encrypted, open-source note-taking where your data stays yours — even from the server.