picomatch vs micromatch vs minimatch: Glob Pattern Matching in Node.js (2026)
TL;DR
picomatch is the fast, lightweight glob matcher — parses glob patterns into regexes, zero dependencies, powers micromatch and many other tools. micromatch is the feature-rich glob library — builds on picomatch, adds brace expansion, negation, filtering, and matching utilities. minimatch is the original npm glob matcher — used by npm internally, widely adopted, slower but battle-tested. In 2026: picomatch for the lowest-level regex conversion, micromatch for full-featured glob matching, minimatch if you need npm-compatible behavior.
Key Takeaways
- picomatch: ~60M weekly downloads — fast regex conversion, zero deps, foundation for micromatch
- micromatch: ~65M weekly downloads — full glob library, brace expansion, filtering, negation
- minimatch: ~40M weekly downloads — npm's glob matcher, oldest, most compatible
- picomatch converts glob → regex:
*.js→/^[^/]*\.js$/ - micromatch adds utilities:
mm.match(files, "*.js"),mm.isMatch(),mm.filter() - minimatch is what npm uses internally for package file matching
Glob Syntax Quick Reference
Pattern Matches
* Any file (no path separator)
** Any path (including nested directories)
*.js All .js files in current directory
**/*.js All .js files in any directory
src/** Everything under src/
{a,b}.js a.js or b.js
[abc].js a.js, b.js, or c.js
!(*.test).js All .js except .test.js
?(a|b).js Optional: .js, a.js, or b.js
+(a|b).js One or more: a.js, ab.js, ba.js, etc.
picomatch
picomatch — fast glob-to-regex:
Basic matching
import picomatch from "picomatch"
// Create a matcher function:
const isMatch = picomatch("*.js")
isMatch("app.js") // true
isMatch("app.ts") // false
isMatch("src/app.js") // false (* doesn't match /)
// Globstar (**):
const isDeep = picomatch("src/**/*.ts")
isDeep("src/index.ts") // true
isDeep("src/utils/helpers.ts") // true
isDeep("lib/index.ts") // false
Pattern options
import picomatch from "picomatch"
// Brace expansion (picomatch supports it):
const isAsset = picomatch("*.{js,ts,css}")
isAsset("app.js") // true
isAsset("app.css") // true
isAsset("app.html") // false
// Negation:
const notTest = picomatch("!*.test.js")
notTest("app.js") // true
notTest("app.test.js") // false
// Case insensitive:
const matcher = picomatch("*.JS", { nocase: true })
matcher("app.js") // true
matcher("app.JS") // true
// Dot files:
const withDots = picomatch("*", { dot: true })
withDots(".gitignore") // true (default: false)
Convert to regex
import picomatch from "picomatch"
// Get the compiled regex:
const { regex } = picomatch.makeRe("src/**/*.{ts,tsx}")
console.log(regex)
// → /^src\/(?:[^/]*\/)*[^/]*\.(?:ts|tsx)$/
// Use regex directly:
regex.test("src/index.ts") // true
regex.test("src/components/App.tsx") // true
// Scan pattern for metadata:
const info = picomatch.scan("src/**/*.ts")
// → { prefix: "src/", base: "src", glob: "**/*.ts", ... }
Performance
picomatch performance:
- Compiles glob → regex once, then reuses
- ~3x faster than minimatch for repeated matching
- Zero dependencies — no overhead
- Used internally by: micromatch, chokidar, fast-glob, anymatch
Tip: Create the matcher once, reuse for many files:
const isMatch = picomatch("**/*.ts") // compile once
files.filter(isMatch) // reuse many times
micromatch
micromatch — full glob matching library:
Matching utilities
import micromatch from "micromatch"
const files = [
"src/index.ts",
"src/utils/helpers.ts",
"src/components/App.tsx",
"tests/index.test.ts",
"README.md",
"package.json",
]
// match() — filter files by pattern:
micromatch.match(files, "src/**/*.ts")
// → ["src/index.ts", "src/utils/helpers.ts"]
micromatch.match(files, "**/*.{ts,tsx}")
// → ["src/index.ts", "src/utils/helpers.ts", "src/components/App.tsx", "tests/index.test.ts"]
// isMatch() — check single file:
micromatch.isMatch("src/index.ts", "src/**/*.ts") // true
micromatch.isMatch("README.md", "**/*.ts") // false
// not() — exclude matching files:
micromatch.not(files, "**/*.test.ts")
// → all files except tests/index.test.ts
Multiple patterns
import micromatch from "micromatch"
// Array of patterns — union:
micromatch.match(files, ["**/*.ts", "**/*.tsx"])
// → all TypeScript files
// Negation patterns — exclude:
micromatch.match(files, ["**/*.ts", "!**/*.test.ts"])
// → .ts files excluding tests
// Filter function:
const isSource = micromatch.matcher(["src/**/*.{ts,tsx}", "!**/*.test.*"])
files.filter(isSource)
// → ["src/index.ts", "src/utils/helpers.ts", "src/components/App.tsx"]
Brace expansion
import micromatch from "micromatch"
// Brace expansion:
micromatch.braces("src/{components,utils}/*.ts")
// → ["src/components/*.ts", "src/utils/*.ts"]
// Numeric ranges:
micromatch.braces("file{1..5}.txt")
// → ["file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt"]
// Nested braces:
micromatch.braces("{src,lib}/{**/*.ts,**/*.js}")
// → ["src/**/*.ts", "src/**/*.js", "lib/**/*.ts", "lib/**/*.js"]
Advanced patterns
import micromatch from "micromatch"
// Extglob patterns:
micromatch.match(files, "src/!(tests)/**/*.ts") // Not in tests/
micromatch.match(files, "src/?(utils|lib)/*.ts") // Optional utils or lib
micromatch.match(files, "src/+(components)/*.tsx") // One or more components
// POSIX character classes:
micromatch.isMatch("a1.ts", "[[:alpha:]][[:digit:]].ts") // true
// Regex-like patterns:
micromatch.match(files, /\.tsx?$/) // Can also accept RegExp
minimatch
minimatch — npm's glob matcher:
Basic usage
import { minimatch } from "minimatch"
// Single file check:
minimatch("src/index.ts", "src/**/*.ts") // true
minimatch("README.md", "**/*.ts") // false
// With options:
minimatch("SRC/Index.ts", "src/**/*.ts", { nocase: true }) // true
minimatch(".gitignore", "*", { dot: true }) // true
Filter files
import { minimatch } from "minimatch"
const files = [
"src/index.ts",
"src/utils/helpers.ts",
"tests/index.test.ts",
"README.md",
]
// Filter:
files.filter((f) => minimatch(f, "src/**/*.ts"))
// → ["src/index.ts", "src/utils/helpers.ts"]
// Filter with Minimatch class (reusable):
import { Minimatch } from "minimatch"
const mm = new Minimatch("**/*.ts")
files.filter((f) => mm.match(f))
// → ["src/index.ts", "src/utils/helpers.ts", "tests/index.test.ts"]
Negation and options
import { minimatch } from "minimatch"
// Negation with !:
minimatch("test.js", "!*.test.js") // true
minimatch("app.test.js", "!*.test.js") // false
// Options:
minimatch("file.ts", "*.ts", {
nocase: true, // Case insensitive
dot: true, // Match dot files
noglobstar: false, // Allow **
nonegate: false, // Allow ! negation
matchBase: true, // Match basename only (like find)
})
// matchBase — match filename part only:
minimatch("src/deep/nested/app.js", "app.js", { matchBase: true })
// → true (matches basename "app.js")
npm compatibility
minimatch is what npm uses for:
- "files" field in package.json
- .npmignore patterns
- workspace patterns
If you're building npm-related tooling, minimatch ensures
exact behavioral parity with npm's own pattern matching.
Feature Comparison
| Feature | picomatch | micromatch | minimatch |
|---|---|---|---|
| Glob → regex | ✅ | ✅ (via picomatch) | ✅ |
| match(files) | ❌ (single) | ✅ | ❌ (single) |
| Multiple patterns | ❌ | ✅ | ❌ |
| Brace expansion | ✅ | ✅ (+ braces()) | ✅ |
| Negation | ✅ | ✅ (in arrays) | ✅ |
| Extglob | ✅ | ✅ | ✅ |
| POSIX classes | ✅ | ✅ | ❌ |
| Pattern scanning | ✅ (scan) | ✅ | ❌ |
| Dot files | Option | Option | Option |
| Case insensitive | Option | Option | Option |
| Dependencies | 0 | 1 (picomatch) | 1 (brace-expansion) |
| Performance | ⚡ Fastest | ⚡ Fast | Slower |
| Weekly downloads | ~60M | ~65M | ~40M |
When to Use Each
Use picomatch if:
- Need the fastest glob-to-regex conversion
- Building your own matching utilities
- Want zero dependencies
- Only need single-pattern, single-file matching
Use micromatch if:
- Need to filter file arrays by glob patterns
- Want multiple pattern support (arrays with negation)
- Need brace expansion utilities
- Building file system tools, bundlers, or linters
Use minimatch if:
- Need npm-compatible pattern matching behavior
- Building npm/package.json tooling
- Want the most battle-tested glob implementation
- Don't need performance-critical matching
Methodology
Download data from npm registry (weekly average, February 2026). Feature comparison based on picomatch v4.x, micromatch v4.x, and minimatch v10.x.