# comby: structural search and replace with a parser-combinator engine

> comby is an OCaml command line tool that matches code by syntax instead of by regular expression, so nested calls, comments and strings stop breaking your rewrites. It is for engineers doing large mechanical edits across many files and languages.

**comby-tools/comby** — A code rewrite tool for structural search and replace that supports ~every language.

- Repository: https://github.com/comby-tools/comby
- Website: https://comby.dev
- Stars: 2,676 · Forks: 74
- Language: OCaml
- License: Apache-2.0
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/comby-tools-comby

## What comby replaces, and for whom

A regular expression matches characters. comby matches structure. The README's own example makes the difference concrete: two C `if` statements whose conditions contain nested parentheses, a comment, and a string literal. A regex that captures exactly those two condition expressions is hard to write and easy to get wrong. comby's pattern is `if (:[condition])` with a language flag, and the replacement is `if (1)`. The `:[condition]` hole absorbs balanced content, so the nested call in one branch and the string literal in the other do not need separate patterns.

The audience is anyone running mechanical edits over a codebase: a library API rename, a migration between two function signatures, a lint rule expressed as a rewrite. Because the tool is driven from the command line, it composes with `git`, `xargs` and CI scripts. The README describes it as supporting roughly every language, which in practice means a C-like syntax family plus a set of specific language parsers, not a semantic model of each language.

## How the matching engine works

The repository layout separates the engine from the front end. There are three opam packages: `comby-kernel.opam`, `comby-semantic.opam`, and `comby.opam`, with sources under `lib/` and `src/`. The topic list on the repository names parser combinators and parsing, which is the honest description of the approach: comby parses enough of a language to know where comments, strings and balanced delimiters are, then matches the pattern against that structure rather than against raw bytes.

That is why the C example works. The hole `:[condition]` is not a `.*` wildcard; it is a placeholder that the engine fills with a balanced expression. The same mechanism explains the boundaries: because the parse is shallow and syntactic, comby cannot tell you that two functions named `parse` in different modules are different functions. It matches text that looks like a call, not a call that resolves to a particular symbol.

## Installing comby and running a first rewrite

The README lists pre-built binaries for macOS, Ubuntu and Windows, plus a Docker image. On macOS the documented command is a single brew invocation.

```bash
brew install comby
```

On Ubuntu the README gives a script that fetches a binary. Note the warning that follows it in the README: the Ubuntu binary links PCRE dynamically, so on Arch or Fedora you may need a symlink such as `sudo ln -s /usr/lib/libpcre.so /usr/lib/libpcre.so.3` (or the `/usr/lib64` variant on Fedora) before the binary will start.

```bash
bash <(curl -sL get-comby.netlify.app)
```

On Windows the documented route is WSL plus an Ubuntu install, then `bash <(curl -sL get.comby.dev)`. The Docker path pulls the published image and runs it against stdin, which is useful for checking behaviour before touching files.

```bash
docker pull comby/comby
docker run -a stdin -a stdout -a stderr -i comby/comby '(:[emoji] hi)' 'bye :[emoji]' lisp -stdin <<< '(hi)'
```

The three positional arguments are the match template, the rewrite template, and the language, with `-stdin` telling comby to read from standard input. The README shows this example producing the rewritten greeting. The same shape applies to files on disk, and the README points to an interactive review mode, shown as a GIF in the repository, for stepping through matches before accepting them. Building from source is documented as well: install opam, create an OCaml 5.1.0 switch, install the OS dependencies (`autoconf libpcre3-dev pkg-config zlib1g-dev m4 libgmp-dev libev4 libsqlite3-dev` on Linux), then `opam install . --deps-only`, `make`, and `make install`.

## Where the syntactic model stops being enough

The limitation is stated by the design itself. comby knows syntax, not semantics. A pattern that matches `:[x].foo()` will match a method call, a field access on a struct, and a call on a value whose type you never intended, because nothing in the pipeline resolves types. On a large codebase with common method names, expect false positives and plan to use the interactive review mode rather than a blind write.

The second constraint is distribution-specific. The README explicitly documents the PCRE symlink workaround for Arch and Fedora, which means the Ubuntu binary is not portable across Linux distributions without intervention. If you cannot run a symlink on your build machines, the documented alternative is building from source, which brings in opam, an OCaml compiler and a list of system libraries. That is a real cost for a tool you might otherwise install in one line.

The third is version drift. The most recent tagged release in the repository is 1.8.1 from 2022-06-28, while the last push to master was on 2026-06-08. Anyone pinning a release is pinning something four years older than the branch head, and the README does not document a release cadence or a support window for older tags.

## comby against sed and against AST rewriters

`sed` is the obvious comparison, and the README addresses it directly rather than dismissing it: sometimes a regex is good enough. The difference is what happens when the target spans nested delimiters. `sed` operates on lines and character classes, so a pattern that must stop at the matching close parenthesis needs either a regex engine with recursion or a hand-rolled approximation. comby's pattern language expresses that boundary as a hole, and the engine enforces balance.

A second comparison is with AST-based rewriters built on a full compiler front end. Those give you type information and can guarantee that a rewrite applies only to a resolved symbol. They also require a working parser and build setup for each language you touch, and they break when the code does not compile. comby trades that guarantee for reach: a shallow parse runs on files that would not pass a build, and the same pattern style carries across languages. If your rewrite needs to distinguish two same-named symbols, comby is the wrong tool and a compiler-integrated rewriter is the right one.

## Licence and the cost of keeping it running

The repository is Apache-2.0, stated in the README badge and in the `LICENSE` file at the top level. That is a permissive licence with an explicit patent grant, which matters if you redistribute a modified comby inside a product. It is not a copyleft licence, so it does not force you to publish changes you make to the tool itself. This is a description of the licence text, not legal advice; check the `LICENSE` file and your own counsel for anything that depends on it.

Upgrade cost is dominated by the release gap. The latest tag is 1.8.1 from 2022-06-28, and the branch head moved on 2026-06-08, so installing from a package manager and building from source can give you materially different binaries. The Makefile shows the build targets you would need to reproduce either one: `make build` for a dev profile, `make release` for a release profile, `make test` to run the test suite, and `make install` to put the binary on your `PATH`. The Dockerfile builds from a pinned base image, `comby/comby:base-dependencies-alpine-3.14`, and runs `opam exec -- make build`, which is the reproducible path if you want the same binary everywhere.

## Conclusion

comby fits teams doing repeated mechanical edits across many languages, where a regex breaks on nested parentheses, strings or comments. It does not fit one-off edits in a single file, or anything needing semantic type information, because the match is syntactic. Before adopting it, check the latest tagged release (1.8.1, 2022-06-28) against the current master branch, and confirm the binary you install links the PCRE library your distribution ships.

## FAQ

### What does "comby" mean?

The README does not give an expansion or a meaning for the name; it uses "comby" throughout as the tool's name and points to comby.dev for usage documentation. The name is not explained in the repository material.

### Is comby a word in Scrabble?

This is a question about the word rather than the tool, and the repository says nothing about it. The material covers comby as a code rewrite tool only.

### How do I install comby?

The README documents `brew install comby` on macOS, a curl script on Ubuntu, WSL plus the Ubuntu script on Windows, and `docker pull comby/comby`. Building from source uses opam with an OCaml 5.1.0 switch, followed by `opam install . --deps-only`, `make`, and `make install`.

### What syntax does comby use for patterns?

Patterns use holes written as `:[name]`, so the README's C example is `if (:[condition])` with a replacement of `if (1)`, plus a flag indicating the language is C-like. The hole absorbs balanced content such as nested calls, strings and comments.

### Does comby work on Windows?

The README's Windows instructions are to install the Windows Subsystem for Linux, install Ubuntu, and then run the Ubuntu install script. There is no native Windows binary documented.

### Which languages does comby support?

The project description says structural search and replace that supports roughly every language, and the repository topics list C, Go, Java, JavaScript, PHP, Python, Rust, Swift and TypeScript among others. The README's own worked example uses a C-like flag.

## Sources

- [comby-tools/comby on GitHub](https://github.com/comby-tools/comby)
- [License: Apache-2.0](https://github.com/comby-tools/comby/blob/master/LICENSE)
- [Project website](https://comby.dev)
- [README](https://github.com/comby-tools/comby/blob/master/README.md)
- [Releases](https://github.com/comby-tools/comby/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/comby-tools-comby
