Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Strip the noise. Keep the code.
uncomment removes comments from source code using tree-sitter's AST — so it is 100% accurate and never touches comment-like text inside strings. It keeps what matters by default (TODO/FIXME, docs, and linting directives) across 300+ languages, with parallel processing and a safe dry-run mode.
AST-accurate · 306 languages · zero false positives · smart preservation · parallel · dry-run
Install · Features · Usage · Configuration · How it works · Contributing
Why uncomment
Regex-based comment strippers guess. They delete a // inside a string literal, mangle a URL in a
docstring, or leave a linting directive your CI depends on. uncomment doesn't guess: it parses your
code into a real syntax tree and removes only the nodes that are genuinely comments.
Originally built to clean up AI-generated code drowning in explanatory comments, it now works on anything with a tree-sitter grammar.
Features
- 100% accurate — tree-sitter AST parsing identifies comments structurally, not by pattern matching
- No false positives — never removes comment-like content from strings
- Smart preservation — keeps TODO/FIXME, docs, and language-specific linting directives by default
- 306 languages — powered by tree-sitter-language-pack, grammars downloaded on demand
- Parallel — multi-threaded processing that scales across cores
- Safe — dry-run mode with line-by-line diffs previews every change before you write
- Configurable — hierarchical TOML config with a smart
initcommand - Built-in benchmarking — optional performance analysis and profiling tools
Installation
| Channel | Command |
|---|---|
| Homebrew (macOS/Linux) | brew tap goldziher/tap && brew install uncomment |
| Cargo (Rust) | cargo install uncomment |
| npm (Node.js) | npm install -g uncomment-cli |
| pip (Python) | pip install uncomment |
Run without installing:
Add --dry-run to preview changes before writing.
Requires Rust 1.70+. npm and pip packages download pre-built binaries automatically.
Quick Start
# Generate a configuration file tuned to your project
# Remove comments from a directory
# Preview changes as a diff, write nothing
Usage
# Single file
# Multiple files / globs
# Also strip doc comments and docstrings
# Also remove TODO and FIXME comments (preserved by default)
# Add custom patterns to preserve
# Process an entire tree with all CPU cores
Run uncomment --help for the full, grouped list of options.
The init command detects the languages in your project and writes a matching .uncommentrc.toml:
# Smart detection — includes only the languages it finds
# All 49 built-in languages
# Interactive selection
# Custom output location / overwrite
Development binaries for benchmarking and profiling are gated behind the bench-tools feature so
they are not installed for regular users:
# Install with extras
# Or run locally
Supported Languages
uncomment ships with 49 built-in language configurations and can process any of the 306 languages in tree-sitter-language-pack — grammars are downloaded automatically on first use, and any language can be added via configuration.
Python (.py, .pyw, .pyi, .pyx, .pxd) · JavaScript (.js, .jsx, .mjs, .cjs) ·
TypeScript (.ts, .tsx, .mts, .cts, .d.ts) · Rust (.rs) · Go (.go) · Java (.java) ·
C (.c, .h) · C++ (.cpp, .cc, .cxx, .hpp, .hxx) · C# (.cs) ·
Ruby (.rb, .rake, .gemspec) · PHP (.php, .phtml) · Elixir (.ex, .exs) · TOML (.toml) ·
JSON (.json) · JSON with Comments (.jsonc) · YAML (.yml, .yaml) ·
HCL/Terraform (.hcl, .tf, .tfvars) · Makefile (Makefile, .mk) ·
Shell/Bash (.sh, .bash, .zsh) · Haskell (.hs, .lhs) · HTML (.html, .htm, .xhtml) ·
CSS (.css) · XML (.xml, .xsd, .xsl, .xslt, .svg) · SQL (.sql) · Kotlin (.kt, .kts) ·
Swift (.swift) · Lua (.lua) · Nix (.nix) · PowerShell (.ps1, .psm1, .psd1) ·
Protobuf (.proto) · INI-like configs (.ini, .cfg, .conf) · Dockerfile (Dockerfile) ·
Scala (.scala, .sc) · Dart (.dart) · R (.r, .R) · Julia (.jl) · Zig (.zig) ·
Clojure (.clj, .cljs, .cljc, .edn) · Elm (.elm) · Erlang (.erl, .hrl) · Vue (.vue) ·
Svelte (.svelte) · SCSS (.scss) · LaTeX (.tex, .sty, .cls) · Fish (.fish) ·
Perl (.pl, .pm) · Groovy (.groovy, .gradle) · OCaml (.ml, .mli) ·
Fortran (.f90, .f95, .f03, .f08)
Preservation Rules
Certain comments are never removed by default — uncomment protects the ones your tooling and teammates rely on.
Always preserved:
- Comments containing
~keep TODO(unless--remove-todo),FIXME(unless--remove-fixme)- Documentation comments (unless
--remove-doc)
| Language | Directives |
|---|---|
| Go | //nolint, //golangci-lint, //staticcheck, //go:generate |
| Python | # noqa, # type: ignore, # mypy:, # pyright:, # ruff:, # pylint:, # flake8:, # fmt: off/on, # black:, # isort:, # bandit:, # pyre-ignore |
| JS/TS | eslint-disable*, @ts-ignore, @ts-expect-error, @ts-nocheck, /// <reference, prettier-ignore, biome-ignore, deno-lint-ignore, v8/c8/istanbul ignore |
| Rust | #[allow], #[deny], #[warn], #[forbid], #[cfg], clippy::, #[rustfmt::skip] |
| Java | @SuppressWarnings, @SuppressFBWarnings, //noinspection, // checkstyle: |
| C/C++ | // NOLINT, // NOLINTNEXTLINE, #pragma, // clang-format off/on |
| Shell | # shellcheck disable, # hadolint ignore |
| YAML | # yamllint disable/enable |
| HCL/Terraform | # tfsec:ignore, # checkov:skip, # trivy:ignore, # tflint-ignore |
| Ruby | # rubocop:disable/enable, # reek:, # standard:disable/enable |
Configuration
uncomment reads a hierarchical TOML configuration, merged highest-to-lowest precedence:
- Command-line flags
- Local
.uncommentrc.toml(closest to the file being processed wins) - Global
~/.config/uncomment/config.toml - Built-in defaults
[]
= false
= false
= false
= ["IMPORTANT", "NOTE", "WARNING"]
= true
= true
[]
= ["py", "pyw", "pyi"]
= ["noqa", "type:", "pragma:", "pylint:"]
[]
# Keep all comments in test files
= false
= false
= false
Any of the 306 tree-sitter-language-pack languages works — grammars download automatically on first use, no manual grammar setup:
[]
= "Hare"
= ["ha"]
= ["comment"]
= ["TODO", "FIXME"]
How It Works
Unlike regex-based tools, uncomment builds a proper Abstract Syntax Tree of your code with tree-sitter, so it distinguishes:
- Real comments vs comment-like content in strings
- Documentation comments vs regular comments
- Inline comments vs standalone comments
- Language-specific metadata that must be preserved
The pipeline is modular: a language registry (49 built-ins + on-demand grammars) feeds an AST visitor that finds comment nodes, a preservation engine decides what to keep, and an output generator emits clean code.
Git Hooks
repos:
- repo: https://github.com/Goldziher/uncomment
rev: v3.3.0
hooks:
- id: uncomment
pre-commit:
commands:
uncomment:
run: uncomment {staged_files}
stage_fixed: true
Performance
AST parsing costs a little more than regex, but the tool is fast and scales well with threads.
- Small files (<1000 lines): ~20-30ms
- Large files (>10000 lines): ~100-200ms
| Threads | Files/second | Speedup |
|---|---|---|
| 1 | 1,500 | 1.0× |
| 4 | 3,900 | 2.6× |
| 8 | 5,100 | 3.4× |
Benchmarked on a large enterprise codebase of ~5,000 mixed-language files. Measure your own with
the built-in benchmark and profile tools (see optional benchmarking tools).
Development
See CONTRIBUTING.md for local development, automation hooks, and release
procedures.
Contributing
Issues and pull requests are welcome. If uncomment is useful to you, consider sponsoring development — it helps keep the project maintained for the community.