Skip to main content

picomatch vs micromatch vs minimatch: Glob Pattern Matching in Node.js (2026)

·PkgPulse Team

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

Featurepicomatchmicromatchminimatch
Glob → regex✅ (via picomatch)
match(files)❌ (single)❌ (single)
Multiple patterns
Brace expansion✅ (+ braces())
Negation✅ (in arrays)
Extglob
POSIX classes
Pattern scanning✅ (scan)
Dot filesOptionOptionOption
Case insensitiveOptionOptionOption
Dependencies01 (picomatch)1 (brace-expansion)
Performance⚡ Fastest⚡ FastSlower
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.

Compare file matching and developer tooling on PkgPulse →

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.