minimatch-fast
Drop-in replacement for minimatch.
Up to 36x faster. Zero vulnerabilities.
npm install minimatch-fast- picomatch engine
- 100% API compatible
- TypeScript
- ESM + CJS
- 402 tests
Why minimatch-fast?
The performance and security upgrade your glob matching needs
Lightning Fast
up to 36x faster than minimatch. Powered by picomatch engine with LRU caching and optimized fast paths for common patterns.
Secure
Not vulnerable to CVE-2022-3517 (ReDoS). Built-in protection against catastrophic backtracking and DoS attacks.
Stable
Never freezes on patterns like {1..1000}. Limits on brace expansion prevent hanging or memory issues.
100% Compatible
Drop-in replacement with identical API. 402 tests ensure full compatibility with minimatch v10.x behavior.
TypeScript Ready
Full TypeScript support with complete type definitions included. No need to install separate @types packages.
Dual Module Support
Works with both ESM and CommonJS. Use import or require() - we support both module systems out of the box.
Performance Benchmarks
Every scenario beats minimatch v10.x — 3 stable consecutive runs, median of 21 rounds, 1000-path corpus
Real-world globbing (warm LRU cache)
The real glob workload: build tools and linters match a handful of patterns against thousands of files. minimatch recompiles on every call; minimatch-fast caches compiled patterns. This asymmetry is an openly acknowledged product feature.
| Pattern | minimatch | minimatch-fast | Speedup |
|---|---|---|---|
{src,lib}/**/*.{js,ts,tsx} | 88.0ms | 2.4ms | 36x faster |
@(foo|bar|baz).js | — | — | ~190x faster |
*.js | — | — | ~64x faster |
**/*.js | — | — | 4.3x faster |
The big numbers come from early rejection: slashless patterns are rejected without compiling for nested paths, because one segment cannot cross /.
Engine vs engine (pre-compiled, no cache)
The most honest comparison: the same pre-compiled pattern on both sides, no cache involved. The engine wins 2.4-12x on every measured pattern shape.
| Pattern | minimatch | minimatch-fast |
|---|---|---|
file[0-9].js | Baseline | 12x faster |
@(foo|bar|baz).js | Baseline | 12x faster |
*.js / !*.test.js / ???.js | Baseline | 8-9x faster |
{src,lib}/**/*.{js,ts,tsx} | Baseline | 3.4x faster |
**/*.js / **/**/**/*.js | Baseline | 2.7x faster |
{src,lib}/*.js | Baseline | 2.4x faster |
Compilation and cold calls
The worst-case workload: one-off calls where every pattern gets compiled. Even there, always above parity.
| Scenario | minimatch | minimatch-fast |
|---|---|---|
Compile {src,lib}/**/*.{js,ts,tsx} | Baseline | 5.7x faster |
Compile @(foo|bar|baz).js (extglob) | Baseline | 3x faster |
Compile *.js / **/*.js | Baseline | 1.6-2.3x faster |
Cold @(foo|bar|baz).js (extglob) | Baseline | ~105x faster |
Cold *.js | Baseline | ~20x faster |
Cold complex braces | Baseline | ~4x faster |
Cold **/*.js | Baseline | 1.1-1.9x faster |
Security Comparison
| Feature | minimatch | minimatch-fast |
|---|---|---|
| CVE-2022-3517 (ReDoS) | Vulnerable | Not affected |
| Pattern {1..1000} | Freezes | Instant |
| Brace expansion limit | None | 10,000 max |
Node.js 22, Linux. Methodology: interleaved A/B/B/A, 5 warmup rounds, median of 21 rounds, 1000-path deterministic corpus, 3 stable consecutive runs. Reproduce with npm run benchmark.
Installation
Two ways to upgrade from minimatch
option 1 Update imports
Install the package and update your import statements:
npm uninstall minimatch
npm install minimatch-fastThen update your imports:
- const minimatch = require('minimatch');
+ const minimatch = require('minimatch-fast');- import minimatch from 'minimatch';
+ import minimatch from 'minimatch-fast';option 2 npm aliasing
Zero code changes required. Use npm's package aliasing:
npm install minimatch@npm:minimatch-fastThis installs minimatch-fast as minimatch, so all your existing imports continue to work without any changes.
Usage Examples
Common patterns and use cases
Basic Matching
import minimatch from 'minimatch-fast';
// Basic matching
minimatch('foo.js', '*.js'); // true
minimatch('bar.txt', '*.js'); // false
// Globstar (recursive)
minimatch('src/utils/helpers.js', '**/*.js'); // true
minimatch('test/foo/bar.spec.ts', '**/*.ts'); // trueMatch Array
import { minimatch } from 'minimatch-fast';
const files = ['foo.js', 'bar.js', 'baz.txt', 'qux.md'];
// Match array of files
minimatch.match(files, '*.js');
// => ['foo.js', 'bar.js']
minimatch.match(files, '*.{js,md}');
// => ['foo.js', 'bar.js', 'qux.md']Filter Function
import { minimatch } from 'minimatch-fast';
const files = ['src/index.js', 'src/utils.js', 'test/foo.spec.js'];
// Create a filter function
const isSource = minimatch.filter('src/**/*.js');
files.filter(isSource);
// => ['src/index.js', 'src/utils.js']Minimatch Class
import { Minimatch } from 'minimatch-fast';
// Pre-compile pattern for repeated matching
const mm = new Minimatch('**/*.js', { dot: true });
// Match multiple files efficiently
mm.match('src/index.js'); // true
mm.match('.eslintrc.js'); // true (dot: true)
mm.match('README.md'); // false
// Access the compiled regex
console.log(mm.regexp); // /^(?:(?!...)...$/Brace Expansion
import { minimatch } from 'minimatch-fast';
// Brace expansion
minimatch.braceExpand('{a,b,c}');
// => ['a', 'b', 'c']
minimatch.braceExpand('{1..5}');
// => ['1', '2', '3', '4', '5']
minimatch.braceExpand('file{A,B}.{js,ts}');
// => ['fileA.js', 'fileA.ts', 'fileB.js', 'fileB.ts']Escape / Unescape
import { minimatch } from 'minimatch-fast';
// Escape special characters
minimatch.escape('[foo].js');
// => '\\[foo\\].js'
// Unescape
minimatch.unescape('\\[foo\\].js');
// => '[foo].js'Glob Pattern Reference
Complete guide to glob pattern syntax
| Pattern | Description | Example |
|---|---|---|
* | Match any characters except path separators | *.js matches foo.js, bar.js |
** | Match any characters including path separators (globstar) | **/*.js matches src/foo.js, a/b/c.js |
? | Match exactly one character (except path separator) | ?.js matches a.js, b.js |
[abc] | Match any character in the set | [abc].js matches a.js, b.js, c.js |
[a-z] | Match any character in the range | [a-z].js matches a.js through z.js |
[!abc] | Match any character NOT in the set | [!a].js matches b.js, c.js (not a.js) |
{a,b,c} | Match any of the comma-separated patterns | {foo,bar}.js matches foo.js, bar.js |
{1..5} | Match numeric range | file{1..3}.js matches file1.js, file2.js, file3.js |
{a..c} | Match alphabetic range | {a..c}.js matches a.js, b.js, c.js |
!pattern | Negate the match | !*.min.js excludes minified files |
?(a|b) | Match zero or one of the patterns | ?(foo).js matches .js, foo.js |
*(a|b) | Match zero or more of the patterns | *(a|b).js matches .js, a.js, ab.js, aab.js |
+(a|b) | Match one or more of the patterns | +(a|b).js matches a.js, ab.js, aab.js |
@(a|b) | Match exactly one of the patterns | @(foo|bar).js matches foo.js, bar.js |
POSIX Character Classes
Full support for POSIX bracket expressions
| Class | Description | Example |
|---|---|---|
[[:alpha:]] | Alphabetic characters (a-z, A-Z) | [[:alpha:]]*.txt matches file.txt |
[[:digit:]] | Numeric digits (0-9) | file[[:digit:]].js matches file1.js |
[[:alnum:]] | Alphanumeric (letters and digits) | [[:alnum:]] matches a, Z, 5 |
[[:space:]] | Whitespace characters | [[:space:]] matches space, tab |
[[:upper:]] | Uppercase letters | [[:upper:]] matches A but not a |
[[:lower:]] | Lowercase letters | [[:lower:]] matches a but not A |
[[:xdigit:]] | Hexadecimal digits (0-9, a-f, A-F) | [[:xdigit:]] matches 0, a, F |
Unicode Support
Full Unicode and emoji support in patterns and filenames
| Pattern | Description | Matches |
|---|---|---|
*.txt | Full Unicode support in filenames | café.txt, 文件.txt, ファイル.txt |
文件夹/*.js | Unicode in patterns | 文件夹/test.js matches |
{🎉,🎊}.txt | Emoji support | 🎉.txt, 🎊.txt |
API Reference
Complete API documentation
minimatch(path, pattern, [options])
Test a path against a pattern. Returns true if the path matches.
Parameters
pathstringThe path to testpatternstringThe glob patternoptionsMinimatchOptionsOptional configuration
Returns
boolean
Example
minimatch('foo.js', '*.js'); // true
minimatch('foo/bar.js', '**/*.js'); // trueminimatch.match(list, pattern, [options])
Filter an array of paths, returning those that match the pattern.
Parameters
liststring[]Array of paths to filterpatternstringThe glob patternoptionsMinimatchOptionsOptional configuration
Returns
string[]
Example
const files = ['a.js', 'b.ts', 'c.js'];
minimatch.match(files, '*.js');
// => ['a.js', 'c.js']minimatch.filter(pattern, [options])
Create a filter function for use with Array.filter().
Parameters
patternstringThe glob patternoptionsMinimatchOptionsOptional configuration
Returns
(path: string) => boolean
Example
const isJS = minimatch.filter('*.js');
['a.js', 'b.ts'].filter(isJS);
// => ['a.js']minimatch.makeRe(pattern, [options])
Create a regular expression from the pattern.
Parameters
patternstringThe glob patternoptionsMinimatchOptionsOptional configuration
Returns
RegExp | false
Example
minimatch.makeRe('*.js');
// => /^(?:(?!\.)...)\.js$/minimatch.braceExpand(pattern, [options])
Expand brace patterns into an array of patterns.
Parameters
patternstringPattern with bracesoptionsMinimatchOptionsOptional configuration
Returns
string[]
Example
minimatch.braceExpand('{a,b}{1,2}');
// => ['a1', 'a2', 'b1', 'b2']minimatch.escape(str, [options])
Escape special glob characters in a string.
Parameters
strstringString to escapeoptions{ windowsPathsNoEscape?: boolean }Optional configuration
Returns
string
Example
minimatch.escape('[foo].js');
// => '\\[foo\\].js'minimatch.unescape(str, [options])
Remove escape characters from a string.
Parameters
strstringString to unescapeoptions{ windowsPathsNoEscape?: boolean }Optional configuration
Returns
string
Example
minimatch.unescape('\\[foo\\].js');
// => '[foo].js'minimatch.defaults(options)
Create a new minimatch function with default options.
Parameters
optionsMinimatchOptionsDefault options to apply
Returns
typeof minimatch
Example
const mm = minimatch.defaults({ nocase: true });
mm('FOO.js', '*.js'); // truenew Minimatch(pattern, [options])
Create a reusable matcher for a pattern. More efficient when matching the same pattern against multiple paths.
Parameters
patternstringThe glob patternoptionsMinimatchOptionsOptional configuration
Returns
Minimatch
Example
const mm = new Minimatch('**/*.js');
mm.match('src/foo.js'); // true
mm.match('test/bar.js'); // trueOptions
Configuration options for fine-tuning pattern matching
Core Options minimatch compatible
| Option | Type | Default | Description |
|---|---|---|---|
dot | boolean | false | Match dotfiles (files starting with .). By default, * and ? do not match leading dots. |
nocase | boolean | false | Perform case-insensitive matching. |
nonegate | boolean | false | Suppress negation behavior with leading !. |
nobrace | boolean | false | Do not expand brace patterns like {a,b,c}. |
noext | boolean | false | Disable extglob patterns like ?(a|b), *(a|b), etc. |
noglobstar | boolean | false | Disable ** matching across directory boundaries. |
nocomment | boolean | false | Suppress treating # as a comment character. |
matchBase | boolean | false | If pattern has no slashes, match basename of the path. foo matches bar/baz/foo. |
partial | boolean | false | Partial match: pattern can match a portion of the path. |
flipNegate | boolean | false | Returns true for negated patterns that do not match. |
preserveMultipleSlashes | boolean | false | Do not collapse multiple slashes (a//b stays as a//b). |
optimizationLevel | number | 1 | Regex optimization level: 0 = none, 1 = safe (default), 2 = aggressive. |
platform | string | process.platform | Platform for path handling: "win32", "darwin", "linux", etc. |
windowsPathsNoEscape | boolean | false | On Windows, treat \ as path separator, not escape character. |
allowWindowsEscape | boolean | platform !== "win32" | Allow \ as escape character on Windows. |
nocaseMagicOnly | boolean | false | Only apply nocase to magic portions of the pattern. |
magicalBraces | boolean | false | Treat brace expansion as magic (affects hasMagic()). |
debug | boolean | false | Enable debug output. |
Extended Options new in v0.3.0
| Option | Type | Default | Description |
|---|---|---|---|
ignore | string | string[] | undefined | Patterns to exclude from matching. |
failglob | boolean | false | Throw error if no matches found (takes precedence over nonull). |
maxLength | number | 65536 | Maximum pattern length. Prevents ReDoS attacks. |
expandRange | function | undefined | Custom function for expanding ranges in brace patterns. |
bash | boolean | false | Follow bash matching rules more strictly. |
contains | boolean | false | Match pattern anywhere in string (not just full match). |
format | function | undefined | Custom function for formatting strings before matching. |
flags | string | undefined | Regex flags to use in generated regex. |
strictBrackets | boolean | false | Throw error if brackets, braces, or parens are imbalanced. |
literalBrackets | boolean | false | Escape brackets to match literal [ and ]. |
keepQuotes | boolean | false | Retain quotes in the generated regex. |
unescape | boolean | false | Remove backslashes preceding escaped characters. |
Callback Options new in v0.3.0
| Option | Type | Default | Description |
|---|---|---|---|
onMatch | function | undefined | Called when a pattern matches. Receives match result object. |
onIgnore | function | undefined | Called when a pattern is ignored. Receives match result object. |
onResult | function | undefined | Called for all results. Receives match result object. |
Examples
ignore
const mm = new Minimatch('**/*.js', {
ignore: ['**/*.test.js', '**/node_modules/**']
});
mm.match('src/app.js'); // true
mm.match('src/app.test.js'); // falsefailglob
// Throw if no matches found
minimatch.match(files, '*.ts', { failglob: true });
// Error: No matches found for pattern: *.tscontains
// Match anywhere in string
minimatch('foobar', 'bar', { contains: true });
// true (matches substring)format
// Transform paths before matching
const mm = new Minimatch('src/*.js', {
format: (s) => s.replace(/^\.\//, '')
});
mm.match('./src/app.js'); // truecallbacks
const mm = new Minimatch('*.js', {
onMatch: (r) => console.log('Match:', r.output),
onResult: (r) => stats[r.isMatch ? 'hits' : 'miss']++
});literalBrackets
// Match literal brackets in filenames
const mm = new Minimatch('[file].js', {
literalBrackets: true
});
mm.match('[file].js'); // trueSecurity
Built-in protection against common vulnerabilities
CVE-2022-3517 Protection
The original minimatch is vulnerable to Regular Expression Denial of Service (ReDoS) via CVE-2022-3517. Malicious patterns can cause catastrophic backtracking, freezing your application.
minimatch-fast uses picomatch internally, which is specifically designed to avoid backtracking issues and is not vulnerable to this CVE.
// CVE-2022-3517 - Vulnerable pattern in minimatch
// This causes catastrophic backtracking (ReDoS)
const pattern = '[!' + 'a'.repeat(50000) + ']';
// In minimatch: hangs for minutes or crashes
minimatch('test', pattern);
// In minimatch-fast: instant, no vulnerability
minimatch('test', pattern); // false, returns immediatelyBrace Expansion Limits
Unconstrained brace expansion can be exploited to create denial of service attacks. A pattern like {1..1000000} would generate a million patterns, consuming all available memory.
minimatch-fast limits brace expansion to 10,000 patterns maximum and range expansion to 1,000 items, preventing DoS attacks.
// Dangerous brace expansion in minimatch
// This creates 1,000,000 patterns and freezes
const pattern = '{1..1000000}';
minimatch.braceExpand(pattern); // Hangs
// In minimatch-fast: limited to 10,000 max
// Returns original pattern if limit exceededInput Validation
The original minimatch accepts invalid inputs that can cause unexpected behavior or runtime errors deep in the call stack.
minimatch-fast validates both path and pattern arguments upfront, throwing descriptive TypeErrors immediately. Pattern length is also limited to prevent DoS.
// minimatch-fast validates input types
// Prevents runtime errors and unexpected behavior
minimatch(null, '*.js'); // TypeError: path must be a string
minimatch('test', undefined); // TypeError: glob pattern must be a string
minimatch(123, '*.js'); // TypeError: path must be a string
// Pattern length limits prevent DoS
const veryLong = 'a'.repeat(100000);
minimatch('test', veryLong); // TypeError: pattern too longSecurity Features
- Not affected by CVE-2022-3517 (ReDoS)
- Maximum 10,000 patterns from brace expansion
- Maximum 1,000 items in range expansion ({1..N})
- No catastrophic backtracking in regex
- Graceful fallback for oversized patterns
- Input type validation for path and pattern
- Pattern length limits (max 65,536 characters)
TypeScript Support
Full type definitions included
minimatch-fast ships with complete TypeScript definitions. All types are exported and ready to use without installing separate @types packages.
import minimatch, {
Minimatch,
MinimatchOptions,
MMRegExp
} from 'minimatch-fast';
// Options with full type support
const options: MinimatchOptions = {
dot: true,
nocase: true,
noglobstar: false
};
// Basic matching
const matches: boolean = minimatch('foo.js', '*.js', options);
// Minimatch class
const mm: Minimatch = new Minimatch('**/*.ts', options);
const isMatch: boolean = mm.match('src/index.ts');
// Get the compiled regex
const regex: MMRegExp | false = mm.makeRe();
// Filter function
const filter: (p: string) => boolean = minimatch.filter('*.js');
// Match array
const files: string[] = minimatch.match(['a.js', 'b.ts'], '*.js');
// Brace expansion
const expanded: string[] = minimatch.braceExpand('{a,b,c}');Exported Types
minimatch- The main functionMinimatch- The Minimatch classMinimatchOptions- Configuration options interfaceMMRegExp- Extended RegExp with index infoParseReturn- Type for parsed pattern segmentsAST- Type for the abstract syntax tree
Testing & Compatibility
Comprehensive test suite ensures reliability
402 tests total
Every release is verified against the original minimatch test suite plus additional tests for edge cases, Windows paths, and security vulnerabilities.
Running Tests
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Run compatibility tests only
npm run test:compatReporting Issues
Found a compatibility issue? Please open an issue on GitHub with:
- The pattern and path that produces different results
- Expected behavior (what minimatch returns)
- Actual behavior (what minimatch-fast returns)
- Any relevant options used
Changelog
Project evolution and version history
- Cache correctness fixes
- hasMagic() and makeRe() parity with minimatch
- escape/unescape 1:1 alignment
- 402 tests
- fixedCache key now includes every matching-affecting option (contains, bash, flags, ignore, maxLength, strictBrackets, literalBrackets, keepQuotes, unescape, magicalBraces)
- fixedhasMagic() returns false for literal patterns, matching minimatch
- fixedmakeRe() honors negated patterns (!*.js), matching minimatch
- fixednonull option no longer leaks between calls through the pattern cache
- changedescape()/unescape() aligned 1:1 with minimatch: braces only escaped with magicalBraces: true
- changedFast paths fall back to the full engine when options they cannot honor are present
- securitymaxLength is now also enforced before fast-path matching
- securityReleases published via npm trusted publishing (OIDC) with Sigstore provenance
- added24 new regression tests (402 total)
- 15 new picomatch options
- Callback support
- Better error messages
- 378 tests
- addedExtended picomatch options: ignore, failglob, maxLength, expandRange, bash, contains, format, flags
- addedBracket options: strictBrackets, literalBrackets, keepQuotes, unescape
- addedCallback options: onMatch, onIgnore, onResult
- changedImproved maxLength error messages with pattern length and limit details
- changedfailglob now shows how many paths were searched
- securitymaxLength now validates for positive finite numbers
- added22 new tests for extended options
- Input validation for path
- Clean code improvements
- Dead code removal
- 356 tests
- securityAdded type validation for path parameter in minimatch()
- changedFixed generic error message to descriptive message
- removedRemoved console.warn from library code
- removedRemoved dead code (hasMagicChars, escapeRegex, hasBraces)
- changedConsistent operators (?? instead of || for defaults)
- addedTests for path validation (5 cases)
- Security audit
- Dependency updates
- Clean code review
- securitySecurity audit completed
- changedUpdated dependencies
- changedClean code improvements
- Pattern length validation
- Landing page
- Benchmarks
- securityAdded pattern length validation (max 65,536 chars)
- addedLanding page with documentation
- addedBenchmark suite comparing with original minimatch
- LRU pattern cache (500 entries)
- Fast paths for simple patterns
- Brace expansion cache (200 entries)
- Cache utility functions
- addedPattern cache for compiled Minimatch instances
- addedFast paths for *, *.js, ???, .* patterns
- addedBrace expansion cache
- addedclearCache() and getCacheSize() utilities
- changedPre-computed regex flags in Minimatch class
- changedOptimized basename extraction
- changedSmarter Windows path normalization
- 100% API compatible with minimatch
- Powered by picomatch engine
- Full TypeScript support
- Dual ESM/CJS exports
- addedInitial release of minimatch-fast
- added100% API compatibility with minimatch v10.x
- addedFull TypeScript support with type definitions
- addedDual ESM and CommonJS module exports
- addedComprehensive test suite (302 tests)
- addedGitHub Actions CI/CD pipeline
- securityNot affected by CVE-2022-3517 (ReDoS)
- securityLimits on brace expansion to prevent DoS