ripgrep-node
This `ripgrep` npm package provides the powerful command-line utility `ripgrep` in a fully cross-platform, dependency-free manner by compiling it to WebAssembly (WASM). As of version 0.3.1, it offers programmatic access to `ripgrep`'s core functionality, suitable for Node.js, Bun, Deno, and even bundler-friendly browser environments without requiring native binaries or post-install scripts. The package embeds the WASM module as a z85+brotli encoded string and leverages WASI for execution, defaulting to Node.js's built-in `node:wasi` for optimal performance when available. Its key differentiator is providing `ripgrep`'s capabilities entirely within the JavaScript ecosystem, making it a drop-in programmatic replacement for native `ripgrep` spawns, with the WASM module dynamically cached to the OS temp directory for subsequent fast access.
Common errors
-
TypeError: WebAssembly.instantiateStreaming is not a function
cause The runtime environment (e.g., older Node.js, specific browser context) does not fully support modern WebAssembly APIs or WASI.fixEnsure you are running on a modern Node.js (16+ is recommended for `node:wasi`), Bun, Deno, or a browser with full WebAssembly/WASI support. Update your runtime or bundler configuration if targeting older environments. -
ERR_REQUIRE_ESM: require() of ES Module [path/to/ripgrep.js] not supported.
cause Attempting to import `ripgrep` using `require()` in a CommonJS module, but the package is an ES Module.fixUse ESM `import { ripgrep } from 'ripgrep';` in your module. If you must use CommonJS, convert your file to an ES Module (e.g., by adding `"type": "module"` to `package.json` or changing file extension to `.mjs`), or use dynamic import: `const { ripgrep } = await import('ripgrep');`. -
`ripgrep` command exits with code `2` or similar error, but no `stderr` output.
cause Ripgrep itself exited with an error, typically due to invalid arguments, inaccessible paths, or internal WASI environment issues, but `stderr` buffering or piping was not enabled.fixWhen calling `ripgrep(args, options)`, set `buffer: true` in options to capture `stdout` and `stderr` as strings in the returned object `{ code, stdout, stderr }`. This will allow you to inspect `stderr` for `ripgrep`'s specific error messages. Also, check `preopens` options if dealing with files outside the current working directory.
Warnings
- gotcha Performance characteristics may differ from the native `ripgrep` binary, as this package runs `ripgrep` compiled to WebAssembly (WASM) via WASI. While optimized with SIMD, raw performance might vary depending on the workload and runtime environment.
- gotcha When providing custom `stdout` or `stderr` streams, TTY auto-detection for `--color=ansi` is skipped. This can result in colorless output if not explicitly specified via `ripgrep` arguments.
- gotcha For streams used with `nodeWasi`, only streams with a numeric `fd` (file descriptor) property are supported. Custom streams without this property may cause unexpected behavior or errors.
- gotcha The WASM module is cached to the OS temp directory (`$TMPDIR/ripgrep-wasm-<hash>.wasm`) on first use. In environments with restricted temporary directory access or strict cleanup policies, this caching mechanism might be affected.
- gotcha Running `ripgrep` via `node:child_process.spawn` with `rgPath` and not explicitly managing stdin can cause `ripgrep` to hang in some versions, as `ripgrep` may default to searching stdin if no path is provided.
Install
-
npm install ripgrep -
yarn add ripgrep -
pnpm add ripgrep
Imports
- ripgrep
const { ripgrep } = require('ripgrep');import { ripgrep } from 'ripgrep'; - rgPath
const { rgPath } = require('ripgrep');import { rgPath } from 'ripgrep';
Quickstart
import { ripgrep, rgPath } from "ripgrep";
import { spawn } from "node:child_process";
import * as fs from 'node:fs';
import * as path from 'node:path';
// Create a dummy file for searching
const tempDir = fs.mkdtempSync(path.join(process.cwd(), 'rg-temp-'));
const filePath = path.join(tempDir, 'test.txt');
fs.writeFileSync(filePath, 'This is a test with TODO item one.\nAnother line with TODO item two.');
async function runRipgrep() {
console.log('--- Running ripgrep programmatically (buffer output) ---');
try {
const { code, stdout, stderr } = await ripgrep(["TODO", tempDir], { buffer: true });
console.log(`Exit Code: ${code}`);
console.log(`STDOUT:\n${stdout}`);
console.log(`STDERR:\n${stderr}`);
} catch (e) {
console.error('Error running ripgrep programmatically:', e);
}
console.log('\n--- Spawning ripgrep as a child process ---');
try {
const child = spawn(rgPath, ["TODO", tempDir], { stdio: "pipe" });
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
child.on('close', (code) => {
console.log(`Child process exited with code ${code}`);
fs.rmSync(tempDir, { recursive: true, force: true }); // Clean up
});
} catch (e) {
console.error('Error spawning ripgrep:', e);
fs.rmSync(tempDir, { recursive: true, force: true }); // Clean up
}
}
runRipgrep();