ast-grep: Code Rewriting & Structural Search CLI
ast-grep is a command-line tool that searches, lints, and rewrites code by matching abstract syntax tree structure instead of raw text, so a pattern like `$A && $A()` catches that shape everywhere regardless of variable names. Reach for it when you need to run a codemod across a large TypeScript or JavaScript codebase without hand-rolling a babel script. Skip it if you only need a one-off text swap — grep or sed is less setup for that.
Understanding ast-grep's Structural Code Matching
ast-grep is a Rust-based CLI that parses source code into an abstract syntax tree with tree-sitter, then matches patterns against that tree's structure rather than raw text. You write a pattern that looks like ordinary code, using `$` plus uppercase letters (like `$MATCH`) as a wildcard for any single AST node. The same matching engine drives three commands: search, lint via YAML rule files, and rewrite.
Core Capabilities for Code Transformation
- ✓Pattern syntax that reads like real code — write `$PATTERN` where an expression would go, and it captures any AST node in that spot without regex escaping.
- ✓`$` plus uppercase wildcards (`$MATCH`, `$A`, etc.) that capture a node once and let you reference it again later in the same pattern or in a `--rewrite` replacement.
- ✓A `--rewrite` flag that turns a matched pattern into an automated code change, run directly from the command line against a `--lang` target.
- ✓YAML rule files for defining lint checks or multi-step rewrites as configuration, instead of a one-off script per rule.
- ✓An AST traversal and manipulation API loosely modeled on jQuery's chaining style, for scripting checks beyond what the CLI flags cover.
- ✓A compiled Rust binary with tree-sitter parsing that the README says takes advantage of multiple CPU cores.
- ✓A browser playground for testing a pattern against sample code before writing any local config.
Who Benefits from ast-grep?
ast-grep fits developers who need to change many call sites the same way: open-source maintainers rolling out a breaking API change, tech leads who want a lint rule that checks for a code shape rather than a text pattern, and anyone running a one-time migration like the Zodios rewrite shown in the README. It's less useful for simple string lookups across files, where plain grep is the faster tool to reach for.
Getting Started with ast-grep
ast-grep installs through several package managers, per the README: `npm install --global @ast-grep/cli` (Node users may need to run `pnpm approve-builds`), `pip install ast-grep-cli`, or `brew install ast-grep`. It's also available via `cargo install ast-grep --locked`, `cargo binstall ast-grep`, Scoop (`scoop install main/ast-grep`), MacPorts (`sudo port install ast-grep`), Nix (`nix-shell -p ast-grep`), and mise (`mise use -g ast-grep`). To build from source, install rustup, clone the repo, and run `cargo install --path ./crates/cli --locked`. The README also points to Repology for packages on other platforms.
Command Line Examples and Patterns
The core command shape is `ast-grep --pattern 'var code = $PATTERN' --rewrite 'let code = new $PATTERN' --lang ts`, which finds every match of the pattern and rewrites it in one pass. The README's own examples show shorthand flags in practice: `ast-grep -p '$A && $A()' -l ts -r '$A?.()'` converts a guarded call into optional chaining, and `ast-grep -p 'new Zodios($URL, $CONF as const,)' -l ts -r 'new Zodios($URL, $CONF)' -i` migrates a Zodios config call. Lint and codemod rules beyond a single-line pattern are written as YAML config rather than passed inline on the command line.
Why Choose ast-grep for Code Manipulation?
- ✓Structural matching doesn't break the way text search does when code gets reformatted or a variable gets renamed — the pattern still matches the same shape.
- ✓No need to write a full AST-manipulation script from scratch for a one-time codemod; the pattern syntax reads like the code you're already writing.
- ✓Installable through package managers most developers already have — npm, pip, cargo, or Homebrew — not a bespoke installer.
- ✓MIT license, so pulling it into a commercial project's CI pipeline doesn't raise a licensing question.
- ✓Lint rules and rewrite rules share the same pattern engine and YAML format, so learning one syntax covers both jobs.
Considerations When Using ast-grep
- △The README doesn't publish benchmark numbers, so any claim about speed on very large codebases rests on the Rust/tree-sitter design, not a measured result.
- △The documentation provided here doesn't list every supported language; confirming grammar support for a less common language means checking ast-grep's own site.
- △Writing a pattern that reliably captures the right AST shape takes more upfront learning than writing a regex, especially if you don't know how your target language's grammar structures expressions.
- △Flags like `-i` show up in the README's own examples without an inline explanation, so a first-time user will likely need outside docs to understand every option.
Comparing ast-grep with Other Tools
Frequently Asked Questions About ast-grep
ast-grep matches code through tree-sitter grammars, and the README's own examples run against TypeScript using the `-l ts` flag. The full supported-language list isn't spelled out in this documentation, so check ast-grep's own site for current grammar coverage.
ast-grep is free and open source, released under the MIT license and hosted publicly on GitHub, where it has 15,402 stars and 424 forks recorded.
Traditional grep matches text line by line, so it can misfire on comments, strings, or code that's only been reformatted. ast-grep instead parses code into an abstract syntax tree via tree-sitter and matches structure, so a pattern like `$A && $A()` finds that shape regardless of variable names or whitespace.
ast-grep supports custom lint rules through YAML configuration files, letting you define pattern-based checks tailored to your own codebase's conventions instead of relying only on built-in rules.
ast-grep has an online playground, linked from the README, where you can test a pattern against sample code in the browser before installing anything locally.
The README doesn't publish benchmark numbers for ast-grep, but the tool is a compiled Rust binary that parses with tree-sitter and, per the README, takes advantage of multiple CPU cores — the architecture you'd want for scanning a large codebase quickly, even without a published number to point to.
The problem it solves
Refactoring across a codebase usually forces a choice between two weak options: a grep/sed pass that matches text and breaks the moment code gets reformatted or a variable renamed, or a full AST transform written with something like babel that takes real setup for a change you might run once. ast-grep sits between those two — its patterns read like ordinary code, so the entry cost is close to grep's, but matching happens against AST structure, so it survives whitespace changes and renames that would defeat a text search.
Best use cases
- •Shipping a rewrite rule alongside a breaking API change so library users can auto-migrate their code instead of following a manual upgrade guide.
- •Encoding team-specific coding conventions as YAML lint rules and running them in CI to catch a code shape that a regex-based linter would miss.
- •Prototyping a vulnerability-pattern check as an AST pattern instead of building a full static-analysis plugin from scratch.
- •One-off framework migrations, like the Zodios config rewrite shown in the README, scripted instead of hand-edited call site by call site.
Related repositories
Curious whether ast-grep is right for you?
Let ChatGPT, Claude, or Perplexity look into it — click below and see what AI actually says about ast-grep.
