mrkeyoor.com_
Thu 06 Aug 01:00 UTC
npmUtilsupdated 05 Aug 2026

globby

globby is fast-glob with the ergonomics filled in: a promise-based API for matching files against glob patterns, with the features you end up hand-rolling otherwise. It supports arrays of patterns with negation ('src/**', '!**/*.test.js'), expands bare directory names into directory/**/*, and, its headline feature, can respect .gitignore and other ignore files, pruning ignored directories like node_modules during traversal instead of filtering afterwards. It is the file-matching layer inside a large slice of build tooling, which is why the download count dwarfs its star count.

Verdict

The most convenient glob API on npm, and the correct pick the moment .gitignore awareness or negated pattern arrays enter the picture. If you just need to match a few files on modern Node, core fs.glob or tinyglobby will do it with less baggage.

API stability4/5The core globby/globbySync/globbyStream API has been steady for years; majors land mostly for Node version floors and the ESM switch, which was disruptive once but is history now.
Docs4/5The README documents every function and option with examples, including performance notes on gitignore handling; there is no separate docs site, and fast-glob's README is required reading for half the options.
Maintenance4/5Actively maintained by Sindre Sorhus with releases through July 2026 and a nearly empty issue tracker (1 open issue or PR), though it is one busy maintainer across thousands of packages rather than a team.
Ecosystem5/5Around 93M weekly downloads as the globbing layer of countless build and lint tools; behavior questions are answered across the fast-glob and globby trackers within minutes of searching.

Use it if

  • You want gitignore-aware file listing: gitignore: true matches Git's actual semantics, including parent .gitignore files and negations, and skips ignored directories during the walk
  • Your patterns come in arrays with negations, and you want ['src/**', '!**/*.spec.js'] to just work without composing ignore options by hand
  • You need streaming iteration over huge trees: globbyStream plus for await keeps memory flat where a giant result array would not
  • You want the small utilities around globbing: isGitIgnored to test single paths, convertPathToPattern for Windows paths, isDynamicPattern to detect glob syntax in user input
Skip it if

Setup reality

npm install globby is dependency-hell-free but comes with two hard platform gates: Node 20+ and ESM-only, so const {globby} = require('globby') throws in CJS and TypeScript projects must have module resolution configured for ESM. The classic runtime gotcha is Windows paths: backslash patterns silently return zero matches, so anything built from path.join needs path.posix.join or convertPathToPattern. Also remember gitignore defaults to false, and results are file paths only unless you set onlyFiles: false.

Patterns

Match files with multiple patternsbasic-glob

import {globby} from 'globby';

const paths = await globby(['src/**/*.ts', '!src/**/*.test.ts']);
console.log(paths);

Negations apply in array order; the return value is a plain array of relative paths using forward slashes on every platform.

List files the way Git sees themrespect-gitignore

import {globby} from 'globby';

const files = await globby('**/*', {gitignore: true});

gitignore is off by default; when on, provably ignored directories like node_modules are skipped during traversal, which is a large performance win on big repos.

Synchronous matching for CLI startup pathssync-matching

import {globbySync} from 'globby';

const configs = globbySync(['*.config.{js,ts,mjs}'], {cwd: process.cwd()});

Same options as the async form; prefer async in servers since the sync walk blocks the event loop for the whole traversal.

Stream matches instead of collecting an arraystream-large-trees

import {globbyStream} from 'globby';

for await (const path of globbyStream('**/*.log', {gitignore: true})) {
  await archive(path);
}

The stream yields paths as the walker finds them, so you can start work immediately and never hold millions of paths in memory.

Build patterns from paths safely on Windowswindows-safe-patterns

import path from 'node:path';
import {globby, convertPathToPattern} from 'globby';

const base = convertPathToPattern('C:/Program Files (x86)');
const files = await globby(`${base}/**/*.dll`);

// or when joining segments:
const pattern = path.posix.join('src', '**', '*.js');

Backslash patterns silently match nothing, and characters like () are glob syntax; convertPathToPattern escapes both problems.

Expand a directory into filtered contentsexpand-directories

import {globby} from 'globby';

const images = await globby('assets', {
  expandDirectories: {extensions: ['png', 'jpg', 'webp']},
});

Bare directory names become dir/**/* by default; turning expandDirectories off means directories only match at all with onlyFiles: false.

Test whether one path is gitignoredcheck-single-path-ignored

import {isGitIgnored} from 'globby';

const isIgnored = await isGitIgnored();
if (isIgnored('dist/bundle.js')) {
  console.log('skipping ignored file');
}

Building the predicate reads all .gitignore files once; reuse the returned function in loops instead of calling isGitIgnored repeatedly.

Respect .prettierignore-style filescustom-ignore-files

import {globby} from 'globby';

const targets = await globby('**/*.{js,css,md}', {
  ignoreFiles: '.prettierignore',
});

Works with any gitignore-syntax file; a specific path like '.prettierignore' is much faster than a recursive '**/.prettierignore' search.

Include dotfiles in matchesmatch-dotfiles

import {globby} from 'globby';

const everything = await globby(['**/*'], {dot: true, gitignore: true});

By default files starting with a dot are invisible to * and **; dot: true also affects the implicit **/* prepended for negation-only patterns.

Handle user-supplied negation-only patternsnegation-only-guard

import {globby} from 'globby';

// user typed only exclusions; do not silently match everything
const result = await globby(userPatterns, {
  expandNegationOnlyPatterns: false,
});

With the default (true), ['!*.json'] implicitly becomes ['**/*', '!*.json']; disabling it returns [] instead, which is safer when patterns are user input.

Get absolute paths or entry objectsabsolute-paths-and-stats

import {globby} from 'globby';

const abs = await globby('src/**/*.ts', {absolute: true});
const entries = await globby('src/**/*.ts', {objectMode: true, stats: true});
for (const e of entries) console.log(e.path, e.stats.size);

These are fast-glob passthrough options; the full option list lives in fast-glob's README, which globby's docs link rather than duplicate.

Detect whether user input is a globdetect-glob-syntax

import {isDynamicPattern} from 'globby';

if (isDynamicPattern(userInput)) {
  files.push(...await globby(userInput));
} else {
  files.push(userInput); // literal path, skip the walk
}

Handy in CLIs that accept both literal paths and patterns; note the answer can depend on options like extglob.

Alternatives

PackageRegistryPick it when
fast-globnpmYou want the same engine with fewer layers and do not need gitignore support or directory expansion.
tinyglobbynpmYou are trimming dependency trees; it covers the common fast-glob/globby surface with only two dependencies.
globnpmYou want the original, zero-compromise-on-compat glob with both sync and CJS support and do not mind a different options API.