# rewrite-clj: a parser that hands your whitespace back

> rewrite-clj reads and writes Clojure, ClojureScript and EDN while preserving whitespace and comments, so tools can edit source code without reformatting it. It is a library rather than a tool, it is the parsing layer under several formatters and language servers, and it is maintained in the clj-commons organisation.

**clj-commons/rewrite-clj** — Rewrite Clojure code and edn

- Repository: https://github.com/clj-commons/rewrite-clj
- Website: https://cljdoc.org/d/rewrite-clj
- Stars: 665 · Forks: 59
- Language: Clojure
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/clj-commons-rewrite-clj

## Whitespace and comments survive the round trip

The one line summary in the README is the whole pitch. rewrite-clj is a library that reads and writes Clojure, ClojureScript and EDN from Clojure and ClojureScript in a whitespace and comment preserving way.

That last clause is the reason the library exists. Reading a form with the standard reader gives you a value, and the information about where it came from in the file, how it was indented and what comment sat above it is gone. rewrite-clj keeps the source as data with positions attached, so a transformation can be applied and written back with the rest of the file untouched.

Two details in that sentence are easy to miss. First, the input formats are three: Clojure source, ClojureScript source, and EDN, the data format from the edn-format project. Second, the implementation language is not fixed to one of them. The library is written in Clojure and can be used from Clojure or from ClojureScript, so the same parsing code can run on a build server and in a browser or in a self-hosted script environment.

The project is hosted under the clj-commons organisation, the licence is MIT, and the artifacts are published to Clojars under the coordinates rewrite-clj/rewrite-clj. The documentation is hosted on cljdoc, and the README carries a badge showing the library is built in to babashka.

## v1 unified the two rewrite libraries

There were once separate projects for Clojure and for ClojureScript, and the merge into one v1 line is the main structural fact about the project.

The status section says that rewrite-clj v1 has been successfully and widely adopted, and the documentation list includes a design document specifically about merging rewrite-clj and rewrite-cljs. There is also a project page on the clj-commons organisation for current priorities, which is a sensible thing to read before you plan around a particular behaviour.

The version history shows the maturity of the current line. Releases include v1.3.59 on 2026-10-01, v1.3.58 on 2026-09-28 and v1.2.57 on 2026-08-29, with the last push on 2026-10-17. The patch numbering at this granularity means the library is still changing in small ways, which is normal for a parser that has to keep up with the language, and it means pinning a version rather than tracking a branch is the sane default for a downstream tool.

The docs themselves are split into a user guide, a developer guide and an FAQ, all under doc/ in the repository, and that structure tells you the library has two audiences: people using it to parse code, and people changing it.

## The canary suite is the compatibility contract

The longest section of the README is a list of projects that use rewrite-clj, and each entry carries a marker. The legend at the bottom explains the three states. A canary-tested project has been tested against the rewrite-clj v1 lib test suite. A canary-needed-patch project required a source change, a minor one, to work with v1. And a not-canary-tested project has no easy way to run the automated unit tests that were found for it.

This is unusual and genuinely useful. Rather than a vague claim of adoption, the project states exactly which downstream tools have been verified against its test suite, and the list names the tools, from adorn for converting Clojure code to Hiccup forms, through cljfmt and cljstyle for formatting and clojure-lsp for language server support, to zprint for pretty printing.

The list also separates the current v1 users from the older ones, with a separate section for projects still on rewrite-clj v0 and rewrite-cljs, and their notes are candid. One entry says the unit tests are failing for it at the time of writing, another says the tests were not version tagged so they could not be run easily, and another says its tests failed when the maintainer tried them.

That candour is a signal about how the project is run. The v0 users are not blocked, and the FAQ in doc/ is where the longer answers live.

## A repository that carries four toolchains

The top level of the repository shows what kind of project this is. There is src/ for the library, test/ and test-isolated/ for tests, test-resources/, and tests.edn. The build side includes build.clj, a build/ directory and deps.edn, so the Clojure build is handled with build.clj.

The ClojureScript side is real too, and not an afterthought. There are shadow-cljs.edn and fig.cljs.edn configuration files, and a package.json that pins the JavaScript test toolchain:

```json
{
  "name": "rewrite-clj",
  "devDependencies": {
    "karma": "6.4.4",
    "karma-chrome-launcher": "3.2.0",
    "karma-cljs-test": "0.1.0",
    "karma-junit-reporter": "2.0.1",
    "karma-spec-reporter": "0.0.37",
    "shadow-cljs": "3.5.7"
  }
}
```

So the ClojureScript tests run under Karma with a Chrome launcher, and shadow-cljs is the build tool for that side. A package-lock.json is committed alongside it, and a .tool-versions file pins tool versions for contributors.

There is also bb.edn, which is the babashka task file, so parts of the build and release process run under babashka itself. A .clj-kondo/ directory means the project lints itself with clj-kondo, .codecov.yml configures coverage reporting, and the repository also carries CHANGELOG.adoc, CODE_OF_CONDUCT.md, CONTRIBUTING.md, an ORIGINATOR file, script/, resources/, template/ and doc/ directories.

## Getting the library and running it on your own code

The README does not give a copy-and-paste dependency snippet, so there is no install command to quote here. What it does give is the coordinate, rewrite-clj/rewrite-clj, published on Clojars, and the documentation on cljdoc at cljdoc.org/d/rewrite-clj, where the current version of the user guide is what you want to read before writing code against it.

The first real use, if you are evaluating the library rather than reading about it, is to parse a file and write it back unchanged. If the output differs from the input, the whitespace and comment preservation promise has failed, and you have found the boundary of what the library covers before you have built anything on top of it.

The second step is to check the formats you actually need. The library claims Clojure, ClojureScript and EDN, and a tool that edits only .clj files has a different risk profile from one that also rewrites .cljs and .edn files in the same pass. The user guide and the FAQ in doc/ are the places where those details are described.

If you are building a formatter rather than a parser, note that you would be duplicating work that already exists. cljfmt and cljstyle both exist for formatting Clojure code, zprint handles pretty printing, and they are listed in the README as users of rewrite-clj. The difference in approach is that a formatter consumes the parsed structure and decides on new layout, while rewrite-clj only gives you a faithful representation of what was there, with the position information you need to change it.

## What rewrite-clj deliberately does not do

The clearest limits come from what the project is not.

It is a parser and a writer, not an evaluator. Nothing in the library turns a form into a running value, and that separation is the point, since evaluating arbitrary source is a different problem with a different risk profile. The EDN format is handled by the same machinery, so the same guarantee about whitespace and comments applies to data files.

It is not a formatter. The list of downstream projects makes the division of work obvious: the formatting tools are separate projects, built on top of this one. A team that reaches for rewrite-clj to tidy up its source is picking the wrong layer.

It is also not a Clojure-only tool in the sense of ClojureScript only support. Both languages are handled, and both are tested in CI, with separate workflows for unit tests, for the libs test suite and for native image tests.

The remaining practical caveat is the v0 and rewrite-cljs era. A number of projects are still on the older libraries, and the README lists them separately rather than pretending they do not exist. If you are maintaining one of those, the migration path is documented in the merging design document, and the v1 lib test suite is the mechanism the project uses to check downstream compatibility, so running it against your own tool is a reasonable first check.

## Conclusion

Adopt rewrite-clj if you are building a Clojure or ClojureScript tool that edits source text and must not disturb formatting, or if you are writing a formatter, a linter or an editor integration where round-tripping fidelity matters. Skip it if you only need to read a value, since plain Clojure evaluation is simpler, and remember that the library does not format code itself, since cljfmt, cljstyle and zprint are the formatters built on top of it. Before you depend on it, read the user guide and the merging design document in doc/, check the current priorities on the clj-commons project page, and pin a version rather than tracking main. The last push was on 2026-10-17 and v1.3.59 was released on 2026-10-01.

## FAQ

### What does rewrite-clj preserve when it rewrites a file?

Whitespace and comments. The library reads and writes Clojure, ClojureScript and EDN in a whitespace and comment preserving way, so a transformation does not reformat the parts of the file it did not touch.

### Where is rewrite-clj published and documented?

The library is published on Clojars under the coordinates rewrite-clj/rewrite-clj, and the documentation is on cljdoc at cljdoc.org/d/rewrite-clj. The README points to a user guide, a developer guide, a design document about merging rewrite-clj and rewrite-cljs, and an FAQ, all under doc/.

### What does the canary-tested marker mean in the rewrite-clj README?

It means the project has been tested against the rewrite-clj v1 lib test suite. The other markers mean a source required a minor change to work with v1, or that there was no easy way to run the automated unit tests for that project.

### Can I use rewrite-clj from ClojureScript?

Yes. The library reads and writes Clojure, ClojureScript and EDN from Clojure and ClojureScript, and the repository carries a separate ClojureScript build with shadow-cljs configuration and Karma based tests.

## Sources

- [clj-commons/rewrite-clj on GitHub](https://github.com/clj-commons/rewrite-clj)
- [License: MIT](https://github.com/clj-commons/rewrite-clj/blob/main/LICENSE)
- [Project website](https://cljdoc.org/d/rewrite-clj)
- [README](https://github.com/clj-commons/rewrite-clj/blob/main/README.md)
- [Releases](https://github.com/clj-commons/rewrite-clj/releases)

---

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