jscpd — Copy/Paste Detector
jscpd v5 is the Rust engine — a self-contained binary, no Node.js runtime. The TypeScript engine (v4: Node.js API, LevelDB/Redis stores) is maintained on the
master-v4branch and published asjscpd@4.
Copy/paste detector for programming source code. Supports 224 language formats, 15 output reporters, and per-line author attribution via git blame. Prebuilt binaries for 8 platforms — no Node.js runtime required.
Packages
| Package | Installs | Use it when |
|---|---|---|
jscpd |
jscpd |
Default install; the jscpd command |
cpd |
cpd |
Shorter command name only |
jscpd (crates.io) |
jscpd + cpd |
Rust-native install; both binaries |
The npm jscpd package installs a single jscpd command that runs the same Rust binary as cpd. For the shorter cpd alias on npm, install the separate cpd package.
Install
# npm — installs the jscpd command
npm install -g jscpd
# crates.io — installs both jscpd and cpd binaries
cargo install jscpd
# Nix — run without installing
nix run github:kucherenko/jscpd -- /path/to/code
# Nix — install permanently
nix profile install github:kucherenko/jscpd
# Homebrew (macOS/Linux)
brew install jscpd
Prebuilt binaries for: macOS arm64/x64, Linux arm64/x64 (glibc + musl), Windows arm64/x64.
Quick Start
jscpd . # scan current directory
jscpd ./src ./lib # scan specific paths
jscpd . --min-tokens 30 --min-lines 3 # tune detection sensitivity
jscpd . --blame --reporters console-full # git blame, side-by-side authors
jscpd . --reporters json,html # write report files
jscpd . --threshold 10 # fail CI if >10% duplicated
jscpd --list # list all supported formats
Options
| Flag | Short | Default | Description |
|---|---|---|---|
--min-tokens |
-k |
50 | Minimum tokens in a clone |
--min-lines |
-l |
5 | Minimum lines in a clone |
--max-lines |
-x |
— | Maximum lines per duplicate block |
--max-size |
-z |
— | Skip files larger than SIZE (e.g. 1mb) |
--mode |
-m |
mild |
Detection mode: mild, weak, strict |
--skip-comments |
— | — | Alias for --mode weak |
--format |
-f |
all | Comma-separated formats to check |
--ignore |
-i |
— | File-level glob patterns to ignore (comma-separated); they match the whole path, so use **/node_modules/** for a directory |
--ignore-pattern |
— | — | Code-level regex patterns; tokens overlapping a match are skipped during detection, e.g. //\\s*cpd-disable (comma-separated) |
--reporters |
-r |
console |
Comma-separated reporters |
--output |
-o |
report |
Output directory for file reporters |
--config |
-c |
— | Path to .jscpd.json config file |
--threshold |
-t |
— | Max duplication % before exit 1 |
--blame |
-b |
— | Enrich clones with git blame data |
--workers |
— | auto | Worker threads for parallel scan |
--skip-local |
— | — | Skip clones within the same directory |
--absolute |
-a |
— | Use absolute paths in reports |
--silent |
-s |
— | Suppress console output |
--list |
— | — | List all supported formats and exit |
Full options: docs/rust.md.
Reporters
| Reporter | Output |
|---|---|
console |
Clone list + statistics table (default) |
console-full |
Source snippets; with --blame shows side-by-side author comparison |
json |
report/jscpd-report.json |
html |
report/jscpd-report.html |
sarif |
report/jscpd-report.sarif (GitHub Code Scanning) |
ai |
Token-efficient output for LLM pipelines |
badge |
report/jscpd-badge.svg + report/jscpd-lines-badge.svg |
Also: xml, csv, markdown, codeclimate, openmetrics, xcode, threshold, silent (15 total).
Config File
Create .jscpd.json in your project root:
{
"minTokens": 30,
"minLines": 3,
"format": ["javascript", "typescript", "python"],
"ignore": ["**/node_modules/**", "**/dist/**", "**/*.min.js"],
"reporters": ["console", "json"],
"output": "report",
"threshold": 5,
"blame": false
}
Supported Formats
224 formats including: JavaScript, TypeScript, Python, Go, Rust, Java, C/C++, C#, Ruby, PHP, Swift, Kotlin, Scala, Vue SFC, Svelte, Astro, Markdown, SQL, HTML, CSS, Bash, Dart, Lua, R, Haskell, Clojure, Elixir, Apex, CFML, and 200+ more.
Run jscpd --list for the full list, or see FORMATS.md.
Cross-format detection: Vue SFC (.vue), Svelte (.svelte), Astro (.astro), and Markdown files are tokenized per-block, enabling duplicate detection across file types.
CI
GitHub Action — installs the Rust engine, runs detection, uploads SARIF to GitHub Code Scanning:
- uses: kucherenko/jscpd@v5
with:
threshold: 5
Pre-commit hook (Husky):
echo 'npx jscpd --threshold 5 --reporters console,silent .' > .husky/pre-commit
Full CI/pre-commit guide: docs/ci-and-hooks.md.
Programmatic Usage (Rust)
use cpd_finder::orchestrate::{RunConfig, run};
let config = RunConfig {
paths: vec!["./src".into()],
min_tokens: 50,
..Default::default()
};
let result = run(&config).unwrap();
println!("Found {} clones", result.clones.len());
println!("Analyzed {} files", result.statistics.total.sources);
Coming from jscpd v4
Flags, config file and reporters are the same. The differences:
| Feature | jscpd v4 (Node.js) | jscpd v5 (Rust) |
|---|---|---|
--store (LevelDB/Redis) |
Persistent store for large repos | Not supported (flag ignored with a warning) |
| Programming API | jscpd() Promise, detectClones() |
Rust crate API; no Node.js API |
--reporters |
All v4 reporters | All except full (use console-full) |
| Output filenames | jscpd-report.json, html/ dir |
jscpd-report.* prefix |
Full table: docs/rust.md. jscpd v4 lives on the master-v4 branch.
Architecture
jscpd (CLI binary)
├── cpd-core — Detection algorithm (Rabin-Karp rolling hash)
├── cpd-tokenizer — Language tokenization (224 formats)
├── cpd-finder — File walking, orchestration, git blame
└── cpd-reporter — Output formatting (15 reporters)
Links
- Homepage
- Documentation
- FORMATS.md — all 224 formats
- Benchmark vs other tools
- AI reporter, MCP server
- GitHub
- Changelog
License
MIT