A fast TypeScript grep — ripgrep reimagined for the Node.js ecosystem.
██████ ██████ ███████ ██████ ████████ ███████
██ ██ ██ ██ ██ ██ ██ ██
██ ███ ██████ █████ ██████ ██ ███████
██ ██ ██ ██ ██ ██ ██ ██
██████ ██ ██ ███████ ██ ██ ███████
grepts is a TypeScript-native grep tool with full ripgrep feature parity. Use it as a CLI or as an in-process Node.js module — no subprocess spawn overhead.
pnpm add grepts# Basic search
grepts "TODO" ./src
# Case insensitive
grepts -i "fixme" ./src
# Regex pattern
grepts "(import|export).*from" ./src
# Word boundary matching
grepts -w "error" ./src
# Only show file names with matches
grepts -l "TODO" .
# Count matches per file
grepts -c "function" ./src
# Glob filter — only search .ts files
grepts -g "*.ts" "interface" ./src
# Max matches per file
grepts -m 5 "TODO" ./src
# Invert match — show lines NOT matching
grepts --invert-match "test" ./src
# Context lines (like grep -C)
grepts -C 3 "error" ./src
grepts -B 2 -A 5 "error" ./src
# Fixed strings (no regex)
grepts -F "array[0]" ./src
# Multiline mode
grepts -U "function.*\n.*return" ./src
# Search hidden files
grepts --hidden "secret" .
# Limit directory depth
grepts --max-depth 2 "TODO" .
# Quiet mode — exit 0 if match found, 1 otherwise
grepts -q "TODO" ./src
# Show version
grepts -v| Flag | Description |
|---|---|
-i, --ignore-case |
Case insensitive search |
-n, --line-number |
Show line numbers (default: on) |
-c, --count |
Show count of matches per file |
-l, --files-with-matches |
Show only file names with matches |
--files-without-match |
Show only file names without matches |
-w, --word-regexp |
Match whole words only |
-F, --fixed-strings |
Treat pattern as literal string |
-g, --glob <pattern> |
Filter files by glob (e.g., *.ts) |
--hidden |
Search hidden files and directories |
--max-depth <n> |
Max directory recursion depth |
-m, --max-count <n> |
Max matches per file |
--invert-match |
Select non-matching lines |
-U, --multiline |
Multiline matching |
-C, --context <n> |
Lines of context around matches |
-B, --before-context <n> |
Lines before match |
-A, --after-context <n> |
Lines after match |
--no-ignore |
Don't respect .gitignore |
--no-color |
Disable color output |
-q, --quiet |
Suppress output, exit code only |
-v, --version |
Show version |
Use grepts as an in-process Node.js library — zero subprocess overhead.
import { search, searchAsync, searchOptionsSchema } from 'grepts';
// Validate and search
const options = searchOptionsSchema.parse({
pattern: 'TODO',
paths: ['./src'],
ignoreCase: true,
});
// Synchronous search
const results = search(options);
for (const result of results) {
console.log(`${result.filePath}: ${result.matchCount} matches`);
for (const match of result.matches) {
console.log(` L${match.lineNumber}: ${match.line}`);
}
}
// Async search (concurrent file I/O)
const asyncResults = await searchAsync(options);Synchronous recursive grep. Reads files with readFileSync.
Async recursive grep. Reads files concurrently with 32-way parallelism.
Zod schema for validating search options. Use .parse() or .safeParse().
interface SearchOptions {
pattern: string; // Regex pattern or literal string
paths: string[]; // Files or directories to search
ignoreCase?: boolean; // Default: false
lineNumber?: boolean; // Default: true
count?: boolean; // Default: false
filesWithMatches?: boolean;
filesWithoutMatch?: boolean;
wordRegexp?: boolean; // Default: false
fixedStrings?: boolean; // Default: false
glob?: string; // e.g., "*.ts"
hidden?: boolean; // Default: false
maxDepth?: number;
maxCount?: number;
context?: number; // Default: 0
beforeContext?: number;
afterContext?: number;
invertMatch?: boolean; // Default: false
multiline?: boolean; // Default: false
respectGitignore?: boolean; // Default: true
color?: boolean; // Default: true
quiet?: boolean; // Default: false
}interface SearchResult {
filePath: string;
matches: MatchInfo[];
matchCount: number;
}
interface MatchInfo {
line: string;
lineNumber: number;
columnStart: number;
columnEnd: number;
}| Feature | grepts | ripgrep |
|---|---|---|
| Regex search | ✅ | ✅ |
| Recursive directory walk | ✅ | ✅ |
| .gitignore support | ✅ | ✅ |
Case insensitive (-i) |
✅ | ✅ |
Line numbers (-n) |
✅ | ✅ |
Match count (-c) |
✅ | ✅ |
Files with matches (-l) |
✅ | ✅ |
| Files without match | ✅ | ✅ |
Word boundary (-w) |
✅ | ✅ |
Fixed strings (-F) |
✅ | ✅ |
Glob filtering (-g) |
✅ | ✅ |
Hidden files (--hidden) |
✅ | ✅ |
Max depth (--max-depth) |
✅ | ✅ |
Max count (-m) |
✅ | ✅ |
| Invert match | ✅ | ✅ |
Multiline (-U) |
✅ | ✅ |
| Color output | ✅ | ✅ |
Quiet mode (-q) |
✅ | ✅ |
Context lines (-C/-A/-B) |
✅ | ✅ |
| Binary file detection | ✅ | ✅ |
| In-process Node.js API | ✅ | ❌ |
| Async concurrent I/O | ✅ | ❌ |
| Zero-overhead integration | ✅ | ❌ |
grepts is 323x faster than ripgrep per invocation when used in-process (no subprocess spawn overhead). Run benchmarks yourself:
pnpm build && pnpm benchSee BENCHMARKS.md for full results.
When integrating search into Node.js tools (IDEs, build systems, linters, watch mode), you have two options:
- Spawn ripgrep → ~5ms per invocation (fork + exec + pipe overhead)
- Call grepts → ~16μs per invocation (in-process function call)
For a single search, 5ms is fine. But IDEs and build tools search hundreds of times per second. That 323x advantage compounds:
| Scenario | ripgrep (subprocess) | grepts (in-process) |
|---|---|---|
| 1 search | 5ms | 16μs |
| 100 searches | 500ms | 1.6ms |
| 1000 searches | 5s | 16ms |
src/
core/ # Node module (importable library)
index.ts # Public API exports
search.ts # Search engine (regex, matching)
search-async.ts # Async parallel search
walker.ts # Directory traversal, gitignore, glob
output.ts # Color formatting
schemas.ts # Zod validation schemas
types.ts # TypeScript types
cli/ # CLI application
cli.ts # Commander.js CLI entry point
bench/ # Benchmark suite
bench.ts # grepts vs ripgrep vs grep benchmarks
__tests__/ # Vitest tests
# Install dependencies
pnpm install
# Type check
pnpm typecheck
# Run tests
pnpm test
# Build
pnpm build
# Run benchmarks
pnpm bench
# Lint
pnpm lintApache-2.0 by Ahmad Awais built with Command Code.
