Copy/Paste Detector for Source Code

jscpd finds duplicated code in 224 languages and fails the build when there is more of it than you allow. One native binary, nothing else to install. Exact copies by default; renamed, near-miss and semantic clones when you ask for them.
Install
macOS and Linux, one binary, no runtime
curl -fsSL https://jscpd.dev/install.sh | bash

Windows, npm, pip, cargo, brew, nix and Docker: all install options →

In your editor: VS Code JetBrains IDEs other editors →

Runs inside GitHub Super Linter, MegaLinter and Codacy · 10M+ npm downloads a month

What jscpd does

One binary, eleven jobs. Each tab shows the command and what it prints on a demo fixture from the jscpd repository.

Copies, found by default

A plain run reports exact copies: the same tokens in two places, whatever the whitespace, layout or comments. Everything from --min-tokens 50 and --min-lines 5 up.Type-1 clones →

fixtures/mcp-demo
$ jscpd .
Clone found (javascript)
- src/invoice.js [1:1 - 6:72] (6 lines, 105 tokens)
src/print/invoice.js [1:1 - 6:72]
Clone found (javascript)
- src/invoice.js [6:71 - 12:2] (7 lines, 93 tokens)
src/print/invoice.js [7:53 - 13:2]
Clone found (javascript)
- src/orders.js [1:1 - 12:2] (12 lines, 124 tokens)
src/reports/orders.js [1:1 - 12:2]
Found 3 clones.

Four kinds of clones, one scan

Exact copies are the default. The other three kinds are opt-in flags, and every clone comes with its kind and a similarity score.
    Exact clones
    jscpd .

    Type-1: identical tokens. Whitespace, layout and comments do not count. Every run reports these, starting from --min-tokens 50 and --min-lines 5.

    Type-1 clones →
    Renamed clones
    jscpd . --ignore-identifiers --ignore-literals

    Type-2: the same code with different variable names or literal values. --ignore-annotations also drops @Decorator lines. Keywords keep their meaning, so return never matches retry. Reported as renamed.

    Type-2 clones →
    Near-miss clones
    jscpd . --max-gap-lines 2 --similarity 0.7

    Type-3: a copy with a few inserted or changed lines (--max-gap-lines N), or a function with the same structure in one of 15 languages (--similarity RATIO, compared by syntax tree). Reported as similar with a score.

    Type-3 clones →
    Semantic clones
    jscpd . --semantic

    Type-4: functions that do the same job with different code, even in another language, like a rule that a Rust backend enforces and a Svelte frontend repeats. A code embedding model compares them inside jscpd after a one-time jscpd --semantic-download. Experimental; reported as semantic with a score.

    Type-4 clones →

Where it runs

Agents repeat helpers. Each diff reads fine on its own, so review misses it. A failing build does not. Four places for the same binary, each about a minute to set up.
    Pre-commit

    Block the commit before the clone lands.

    .husky/pre-commit
    npx jscpd --threshold 3 .
    pre-commit framework, Husky, plain git hook →
    CI gate

    Fail the pull request when duplication crosses the line. SARIF goes to GitHub Code Scanning; GitLab gets Code Quality and metrics reports.

    # .github/workflows/jscpd.yml
    - uses: kucherenko/jscpd@v5
      with:
        threshold: 3
    
    GitHub Action, GitLab CI, generic CI →
    Coding agents

    Give the agent the same detector over MCP, so it checks for clones before it writes more. Five skills teach it the whole loop: find duplicates, refactor them, remove dead code, check that the numbers improved.

    // MCP client config
    { "mcpServers": { "jscpd": {
        "command": "jscpd", "args": ["--mcp", "."] } } }
    
    skills for Claude, Copilot, Gemini and Cursor
    npx skills add kucherenko/jscpd
    MCP server → Agent skills →
    Editors

    The same findings as diagnostics while you type, with "Go to the other copy" on every clone.

    -- init.lua, Neovim 0.11+
    vim.lsp.config('jscpd', { cmd = { 'jscpd', '--lsp' },
      root_markers = { '.jscpd.json', '.git' } })
    vim.lsp.enable('jscpd')
    
    Neovim, Helix, Sublime Text, Emacs, JetBrains →

Who uses jscpd

From GitHub's official linter to enterprise codebases. 54 papers and 54 articles describe how teams and researchers use it.

Beyond duplicates

The same binary reports a project health score and dashboard, dead code in JavaScript, TypeScript and Python, the duplication trend over git history, how far a port to another language has come, and a compact report for LLMs. Each is one flag: --dashboard, --dead-code, --history, --compare, --reporters ai. Boundary rules in the config file keep the code of a module out of the others and fail the build when a copy turns up.