
fastmod: Fast regex-based replacements for codebases
fastmod overview
fastmod is a fast partial replacement tool designed for codebases. It uses the Rust regex crate to find patterns and replace them across files, with sensible defaults and a few handy flags for common tasks.
Quick start: simple replacements
Replace a regex in all files of the current directory, skipping ignored files:
fastmod {{regex}} {{replacement}}
This runs the replacement in every file under the current directory, respecting .ignore and .gitignore patterns. If you’re just trying something small, this is the simplest way to experiment.
Case-insensitive replacements
To perform a case-insensitive replacement in specific files or directories, use:
fastmod --ignore-case {{regex}} {{replacement}} -- {{path/to/file path/to/directory ...}}
The —ignore-case flag applies to the regex search, not to the filesystem paths. It’s handy when you know the target strings may vary in case.
Directory-scoped, with glob filters
If you want to search within a directory and limit candidate files by a glob pattern, you can combine —dir and —iglob:
fastmod {{regex}} {{replacement}} --dir {{path/to/directory}} --iglob {{'**/*.{js,json}'}}
This restricts work to files matching the glob, which can reduce accidental edits and speed up the run.
Exact-string replacements (no regex)
When you need to replace a literal string (no regex interpretation), use —fixed-strings:
fastmod --fixed-strings {{exact_string}} {{replacement}} --extensions {{json,js}}
This is safer when you know the exact text and want to avoid regex metacharacters triggering unintended matches.
Non-interactive, accepted changes only
To perform replacements without prompting for confirmation (and to disable regex mode), use:
fastmod --accept-all --fixed-strings {{exact_string}} {{replacement}}
This is convenient in automation, CI, or when you’re confident about the change. Note that —accept-all bypasses the interactive prompt, so review your exact_string and replacement carefully.
If you also want to see which files changed without stopping the run, add —print-changed-files:
fastmod --accept-all --print-changed-files --fixed-strings {{exact_string}} {{replacement}}
This helps you verify the impact in large codebases.
Practical examples
- Replace a deprecated API name across a repository:
fastmod --ignore-case "oldApiName" "newApiName" -- {{src tests}}
- Update a version string in package.json and related config files using exact strings:
fastmod --fixed-strings "version": "1.2.3" "version": "1.3.0" --extensions json
- Bulk rename a function in JavaScript files without touching other languages:
fastmod --ignore-case --dir ./frontend --iglob '**/*.js' "function oldName(" "function newName("
Common pitfalls to watch out for
- Regex vs. fixed strings: If you don’t need regex features, prefer —fixed-strings to avoid unintended matches.
- Over-broad patterns: A regex like ”.*” can touch every file. Start with a narrow pattern and broaden it only after tests.
- Ignored files: .ignore and .gitignore influence what fastmod processes. If a file is ignored, it won’t be touched, even if you expected it to be included.
- Backups and review: For high-risk changes, consider running in a test branch and using —print-changed-files to review edits before committing.
Workflow tips
- Start local: run without —accept-all to see what would change and confirm each replacement.
- Narrow scope: use —dir and —iglob to limit the target set to relevant files.
- Logs: combine with —print-changed-files to build a changelist you can review.
When to choose fastmod
- You need high-speed, pattern-based edits across many files.
- You want a safer alternative to ad-hoc sed scripts with built-in ignore handling.
- You prefer a Rust-powered tool with a straightforward CLI and common options.
Summary
fastmod offers a pragmatic approach to large-scale text replacements with sensible defaults, support for case-insensitive and fixed-string modes, and helpful options to review changes before applying them. Start simple, test in a controlled scope, and use the non-interactive modes only when you’re confident in the exact strings involved.