# Configuration

> Configure jscpd for your project.

## Configuration File

Create a `.jscpd.json` file in your project root to configure jscpd:

```json [.jscpd.json]
{
  "threshold": 0,
  "reporters": ["html", "console"],
  "ignore": ["**/__snapshots__/**", "**/node_modules/**"],
  "absolute": true,
  "minLines": 5,
  "minTokens": 50
}
```

## CLI Options

<table>
<thead>
  <tr>
    <th>
      Option
    </th>
    
    <th>
      Description
    </th>
    
    <th>
      Default
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        -V
      </code>
      
      , <code>
        --version
      </code>
    </td>
    
    <td>
      Output the version number
    </td>
    
    <td>
      -
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -l
      </code>
      
      , <code>
        --min-lines
      </code>
    </td>
    
    <td>
      Minimum size of duplication in code lines
    </td>
    
    <td>
      5
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -k
      </code>
      
      , <code>
        --min-tokens
      </code>
    </td>
    
    <td>
      Minimum size of duplication in code tokens
    </td>
    
    <td>
      50
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -x
      </code>
      
      , <code>
        --max-lines
      </code>
    </td>
    
    <td>
      Maximum size of source in lines
    </td>
    
    <td>
      1000
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -z
      </code>
      
      , <code>
        --max-size
      </code>
    </td>
    
    <td>
      Maximum size of source in bytes (e.g. <code>
        1kb
      </code>
      
      , <code>
        1mb
      </code>
      
      , <code>
        120kb
      </code>
      
      )
    </td>
    
    <td>
      <code>
        100kb
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -t
      </code>
      
      , <code>
        --threshold
      </code>
    </td>
    
    <td>
      Threshold for duplication, in case duplications >= threshold jscpd will exit with error
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -c
      </code>
      
      , <code>
        --config
      </code>
    </td>
    
    <td>
      Path to config file (default is <code>
        .jscpd.json
      </code>
      
       in scanned <code>
        <path>
      </code>
      
      )
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -i
      </code>
      
      , <code>
        --ignore
      </code>
    </td>
    
    <td>
      Glob pattern for files to exclude from duplication detection
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --ignore-pattern
      </code>
    </td>
    
    <td>
      Ignore code blocks matching the regexp patterns
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -r
      </code>
      
      , <code>
        --reporters
      </code>
    </td>
    
    <td>
      Reporters or list of reporters separated with comma to use
    </td>
    
    <td>
      <code>
        time,console
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -o
      </code>
      
      , <code>
        --output
      </code>
    </td>
    
    <td>
      Path for reports
    </td>
    
    <td>
      <code>
        ./report/
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -m
      </code>
      
      , <code>
        --mode
      </code>
    </td>
    
    <td>
      Mode of quality of search: <code>
        strict
      </code>
      
      , <code>
        mild
      </code>
      
      , <code>
        weak
      </code>
    </td>
    
    <td>
      <code>
        mild
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -f
      </code>
      
      , <code>
        --format
      </code>
    </td>
    
    <td>
      Format or formats separated by comma to detect (e.g. <code>
        php,javascript,python
      </code>
      
      )
    </td>
    
    <td>
      all formats
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -p
      </code>
      
      , <code>
        --pattern
      </code>
    </td>
    
    <td>
      Glob pattern to file search (e.g. <code>
        **/*.txt
      </code>
      
      )
    </td>
    
    <td>
      -
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -b
      </code>
      
      , <code>
        --blame
      </code>
    </td>
    
    <td>
      Blame authors of duplications (get information about authors from git)
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -s
      </code>
      
      , <code>
        --silent
      </code>
    </td>
    
    <td>
      Do not write detection progress and result to console
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --store
      </code>
    </td>
    
    <td>
      Accepted for compatibility; external store backend not supported in v5 (detection is fast enough without it)
    </td>
    
    <td>
      —
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --store-path
      </code>
    </td>
    
    <td>
      Accepted for compatibility; not used in v5
    </td>
    
    <td>
      —
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -w
      </code>
      
      , <code>
        --workers
      </code>
    </td>
    
    <td>
      Number of worker threads for parallel detection (default: auto, uses all CPU cores)
    </td>
    
    <td>
      auto
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -a
      </code>
      
      , <code>
        --absolute
      </code>
    </td>
    
    <td>
      Use absolute path in reports
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --follow-symlinks
      </code>
    </td>
    
    <td>
      Follow symbolic links
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --ignore-case
      </code>
    </td>
    
    <td>
      Ignore case of symbols in code (experimental)
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --no-gitignore
      </code>
    </td>
    
    <td>
      Ignore files from <code>
        .gitignore
      </code>
      
       file
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --formats-exts
      </code>
    </td>
    
    <td>
      List of formats with file extensions (e.g. <code>
        javascript:es,es6;dart:dt
      </code>
      
      )
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --formats-names
      </code>
    </td>
    
    <td>
      List of formats with specific filenames (e.g. <code>
        makefile:Makefile,GNUmakefile;docker:Dockerfile
      </code>
      
      )
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --cross-formats
      </code>
    </td>
    
    <td>
      Groups of related formats to compare together (e.g. <code>
        javascript,typescript;css,scss
      </code>
      
       or the <code>
        js-ts
      </code>
      
       preset)
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -v
      </code>
      
      , <code>
        --verbose
      </code>
    </td>
    
    <td>
      Show full information during detection process
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --no-colors
      </code>
    </td>
    
    <td>
      Disable ANSI color output
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --list
      </code>
    </td>
    
    <td>
      Show list of total supported formats
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --skip-local
      </code>
    </td>
    
    <td>
      Skip duplicates in local folders, just detect cross folders duplications
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --exit-code
      </code>
    </td>
    
    <td>
      Exit code to use when code duplications are detected
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --no-tips
      </code>
    </td>
    
    <td>
      Do not print tips and promotional messages after detection
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --skip-comments
      </code>
    </td>
    
    <td>
      Ignore comments during detection (alias for <code>
        --mode weak
      </code>
      
      )
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        -h
      </code>
      
      , <code>
        --help
      </code>
    </td>
    
    <td>
      Display help for command
    </td>
    
    <td>
      -
    </td>
  </tr>
</tbody>
</table>

## Examples

### Basic scan

```bash
jscpd ./src
```

### With pattern matching

```bash
jscpd --pattern "**/*.ts" ./src
```

### Multiple reporters

```bash
jscpd --reporters html,json,console ./src
```

### Custom threshold

Fail if duplication exceeds 5%:

```bash
jscpd --threshold 5 ./src
```

### Ignore specific patterns

```bash
jscpd --ignore "**/*.test.ts,**/__mocks__/**" ./src
```

### Skip comments (weak mode)

Use `--skip-comments` as a shorthand for `--mode weak`:

```bash
jscpd --skip-comments ./src
```

### Map filenames to formats

For extensionless files like `Makefile` and `Dockerfile`:

```bash
jscpd --formats-names "makefile:Makefile,GNUmakefile;docker:Dockerfile" ./src
```

### Detect clones across related formats

Compare JavaScript and TypeScript files in one pool (see [Cross-Format Detection](#cross-format-detection)):

```bash
jscpd --cross-formats "js-ts" ./src
```

### Parallel detection with workers

Control the number of threads for detection:

```bash
jscpd --workers 4 ./src
```

### Suppress tips in CI

Tips are automatically suppressed when `--silent` is active. To suppress manually:

```bash
jscpd --no-tips ./src
```

### Show full information during detection

```bash
jscpd --verbose ./src
```

### Cross-folder detection only

```bash
jscpd --skip-local /path/to/folder1/ /path/to/folder2/
```

### Ignore case in code

```bash
jscpd --ignore-case ./src
```

### Don't follow symlinks

By default, symlinks are not followed. Use `--follow-symlinks` to follow them:

```bash
jscpd --follow-symlinks ./src
```

### Ignore blocks by regexp pattern

```bash
jscpd --ignore-pattern "import.*from\s*'.*'" ./src
```

## Package.json Configuration

You can also configure jscpd in your `package.json`:

```json [package.json]
{
  "jscpd": {
    "threshold": 0,
    "reporters": ["html", "console"],
    "ignore": ["**/node_modules/**"],
    "absolute": true,
    "gitignore": true
  }
}
```

## Modes

The `--mode` option controls detection quality:

- `strict` — use all types of symbols as token, skip only blocks marked as ignored
- `mild` — skip blocks marked as ignored and new lines and empty symbols (**default**)
- `weak` — skip blocks marked as ignored and new lines and empty symbols and comments

## Cross-Format Detection

jscpd v5+ supports **cross-format detection** for multi-block file types:

- **Vue SFC** (`.vue`) — `<script>`, `<template>`, `<style>` blocks tokenized separately
- **Svelte** (`.svelte`) — script and style blocks tokenized independently
- **Astro** (`.astro`) — frontmatter and template sections tokenized independently
- **Markdown** (`.md`) — fenced code blocks tokenized by language

This means a `<script>` block in a `.vue` file can be matched against a `.ts` file, and a fenced Python code block in Markdown can match a `.py` file.

### Cross-Format Groups (`--cross-formats`)

Since **v5.0.14**, `--cross-formats` defines groups of *related formats* that share one comparison pool, so a block duplicated between a `.js` and a `.ts` file is reported as a clone. By default each format is only compared against itself.

```bash
# One group: compare JavaScript and TypeScript together
jscpd --cross-formats "javascript,typescript" ./src

# Preset covering javascript, jsx, typescript, tsx
jscpd --cross-formats "js-ts" ./src

# Multiple groups, separated by ";"
jscpd --cross-formats "javascript,typescript;css,scss" ./src
```

Rules and behavior:

- Groups are comma-separated format names; multiple groups are separated by `;`. A group needs at least two formats, and groups sharing a format are merged into one pool.
- When a group mixes TypeScript with JavaScript, TS files are compared with erasable type syntax stripped, so `function f(a: number): void` matches `function f(a)`. Reported positions still reference the original source.
- In per-format statistics, a cross-format clone is attributed to one member format of the group.

In `.jscpd.json` or `package.json` the key is `crossFormats` (alias `cross-formats`) and accepts a string, an array of strings, or an array of arrays:

```json [.jscpd.json]
{
  "crossFormats": [["javascript", "typescript"], ["css", "scss"]]
}
```

### Breaking Change for Vue Users

Vue files are no longer tokenized as `markup`. Each block uses its resolved sub-format (`javascript`, `typescript`, `css`, `scss`, etc.). Any tooling that relied on `.vue` clones being reported under `markup` must be updated.

## Shebang Detection

jscpd can detect duplications in script files that have no file extension by reading the `#!` shebang line:

<table>
<thead>
  <tr>
    <th>
      Interpreter
    </th>
    
    <th>
      Detected as
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        bash
      </code>
      
      , <code>
        sh
      </code>
      
      , <code>
        zsh
      </code>
      
      , <code>
        fish
      </code>
      
      , <code>
        dash
      </code>
      
      , <code>
        ksh
      </code>
    </td>
    
    <td>
      <code>
        shell
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        python
      </code>
      
      , <code>
        python3
      </code>
      
      , <code>
        python2
      </code>
    </td>
    
    <td>
      <code>
        python
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        node
      </code>
      
      , <code>
        nodejs
      </code>
    </td>
    
    <td>
      <code>
        javascript
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ruby
      </code>
    </td>
    
    <td>
      <code>
        ruby
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        perl
      </code>
    </td>
    
    <td>
      <code>
        perl
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        php
      </code>
    </td>
    
    <td>
      <code>
        php
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lua
      </code>
    </td>
    
    <td>
      <code>
        lua
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tclsh
      </code>
      
      , <code>
        wish
      </code>
    </td>
    
    <td>
      <code>
        tcl
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        Rscript
      </code>
    </td>
    
    <td>
      <code>
        r
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        groovy
      </code>
    </td>
    
    <td>
      <code>
        groovy
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        swift
      </code>
    </td>
    
    <td>
      <code>
        swift
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        kotlin
      </code>
    </td>
    
    <td>
      <code>
        kotlin
      </code>
    </td>
  </tr>
</tbody>
</table>

Both direct (`#!/usr/bin/bash`) and `env`-mediated (`#!/usr/bin/env python3`) shebangs are supported. Version suffixes are stripped automatically (`python3.11` → `python`).

## Ignored Blocks

Mark blocks in code as ignored:

```javascript
/* jscpd:ignore-start */
import lodash from 'lodash';
import React from 'react';
import {User} from './models';
import {UserService} from './services';
/* jscpd:ignore-end */
```

```html
<!--
// jscpd:ignore-start
-->
<meta data-react-helmet="true" name="theme-color" content="#cb3837"/>
<link data-react-helmet="true" rel="stylesheet" href="https://static.npmjs.com/103af5b8a2b3c971cba419755f3a67bc.css"/>
<!--
// jscpd:ignore-end
-->
```
