> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fallow.tools/llms.txt
> Use this file to discover all available pages before exploring further.

# Code duplication

> Detect copy-pasted code blocks across your TypeScript and JavaScript codebase. Built in to the same binary as dead-code, dependency, complexity, and architecture analysis.

`fallow dupes` finds duplicated code blocks across your entire codebase. jscpd v5 is faster for raw duplication scanning on the current README benchmark fixtures; fallow's advantage is running duplication inside the same audit flow as dead code, dependency, complexity, and architecture checks.

```bash theme={null}
fallow dupes
```

## Why built-in duplication matters

Most dead-code analysis tools stop at finding unused exports and unreachable files. Fallow goes further: it includes duplication detection in the same binary, using the same module graph. This means you can cross-reference dead code with duplication in a single pass.

When you run `fallow dead-code --include-dupes`, fallow identifies code blocks that are both duplicated and unused. These are the highest-value cleanup targets: removing them eliminates dead code and reduces duplication simultaneously.

Running duplication analysis alongside dead-code detection also means:

* **One tool, one config, one CI step**: No need to install and configure a separate duplication detector
* **Shared file discovery**: The same ignore patterns, entry points, and workspace config apply to both analyses
* **Cross-analysis insights**: Clone families that span unused files are flagged as combined findings
* **Consistent output formats**: JSON, SARIF, markdown, compact, and CodeClimate output work the same way for duplication as for dead code

## Detection modes

<Tabs>
  <Tab title="Strict">
    Exact token-for-token clones only. No normalization is applied; the code must be character-identical after tokenization.

    ```bash theme={null}
    fallow dupes --mode strict
    ```

    Best for finding exact copy-paste where nothing was changed.
  </Tab>

  <Tab title="Mild (default)">
    The default mode. Strict and mild modes produce identical results. AST-based tokenization already strips whitespace and comments before comparison.

    ```bash theme={null}
    fallow dupes --mode mild
    ```

    The recommended starting point for general-purpose detection.
  </Tab>

  <Tab title="Weak">
    Matches clones even when string literal values differ. Variable names must still match.

    ```bash theme={null}
    fallow dupes --mode weak
    ```

    Good for finding code that was duplicated and only had strings (URLs, messages, labels) changed.
  </Tab>

  <Tab title="Semantic">
    Catches clones with renamed variables and different literal values. Uses token-type normalization to match structurally equivalent code.

    ```bash theme={null}
    fallow dupes --mode semantic
    ```

    The most aggressive mode. Finds code that was copied and then adapted with new variable names and values.
  </Tab>
</Tabs>

<Tip>
  Start with `mild` mode (default). Upgrade to `semantic` when you want to catch clones with renamed variables.
</Tip>

<Info>
  `dupes --mode semantic` still compares normalized code structure. To find
  complete functions that may share intent despite different structure, use
  the separate, opt-in [`fallow similar-code`](/analysis/similar-code)
  workflow. Its model-backed results are always unverified and require review.
</Info>

### Near-miss clones

Add `--near` to include function-scoped clones with small structural edits:

```bash theme={null}
fallow dupes --near
```

Near-miss detection uses semantic token normalization and requires at least 80% shingle similarity between every pair in a group. It runs alongside exact clone detection and remains opt-in because it does more work and can surface code that needs human review. Set `duplicates.near` to `true` to enable it by default, or use `fallow.duplication.near` in VS Code.

Here's what typical output looks like:

```bash title="$ fallow dupes" theme={null}
● Duplicates (3 clone groups)

     57 lines  2 instances
    src/components/Calendar/CalendarMonth.stories.tsx:597-653
    src/components/Calendar/CalendarYear.stories.tsx:818-874

     42 lines  3 instances
    src/features/forecasting/server/procedures/analytics.ts:141-181
    src/features/forecasting/server/procedures/cashflow.ts:153-194
    src/features/forecasting/server/procedures/income.ts:590-631

  Identical code blocks detected via suffix-array analysis, https://docs.fallow.tools/explanations/duplication#clone-groups

✓ 27,255 lines (19.4%) duplicated across 398 files (0.23s)
```

In semantic mode, fallow also reports renamed identifiers:

```bash title="$ fallow dupes --mode semantic" theme={null}
● Duplicates (2 clone groups)

    196 lines  2 instances
    src/lib/dutch-holidays.ts:193-388
    src/lib/dutch-holidays.ts:389-584
    Renamed: holidays2024→holidays2025, year2024→year2025

     42 lines  3 instances
    src/features/forecasting/server/procedures/analytics.ts:141-181
    src/features/forecasting/server/procedures/cashflow.ts:153-194
    src/features/forecasting/server/procedures/income.ts:590-631
    Renamed: analyticsData→cashflowData→incomeData

  Identical code blocks detected via suffix-array analysis, https://docs.fallow.tools/explanations/duplication#clone-groups

✗ 94,457 lines (67.2%) duplicated across 775 files (3.74s)
```

## Thresholds and limits

```bash theme={null}
fallow dupes --min-tokens 50        # Minimum tokens per clone (default: 50)
fallow dupes --min-lines 5          # Minimum lines per clone (default: 5)
fallow dupes --min-occurrences 3    # Only report clones repeated 3+ times (default: 2)
fallow dupes --threshold 5          # Fail if duplication exceeds 5%
fallow dupes --skip-local           # Only cross-directory duplicates
```

### Minimum occurrences

By default fallow reports every duplicated pair (`minOccurrences: 2`). If you follow the "rule of three" and only want to refactor logic once it appears in three or more places, raise the threshold:

```jsonc theme={null}
{
  "duplicates": {
    "minOccurrences": 3
  }
}
```

Values below `2` are rejected, since a single occurrence is not a duplicate. Raising this skips context-sensitive pairs and focuses on widespread copy-paste worth abstracting. The VS Code extension exposes the same control as the `fallow.duplication.minOccurrences` setting.

### Spread-aware ranking

Fallow multiplies duplicated token count by occurrence count, then applies a spread boost. Spread is the maximum directory-tree distance between copies. Copies in the same file use one spread step per 250 lines of separation. The boost is capped at 15%, so larger and more repeated clones remain the main priority.

The default report and `--top` use this order. JSON output includes `spread` on every clone group, plus `similarity` for near-miss groups.

### Reviewed clone groups

Use `duplicates.ignoredClones` when a specific clone group is intentional but you want other duplication findings to remain active:

```jsonc theme={null}
{
  "duplicates": {
    "ignoredClones": ["dup:6f12ab34:2"]
  }
}
```

Each entry combines the group's `fingerprint` with its instance count. Copy the fingerprint from the human listing or `clone_groups[].fingerprint` in JSON, then append `:<instance_count>`. A token change or a new copy makes the group reportable again. Formatting-only edits keep the same fingerprint.

JSON output sets `stats.clone_groups_ignored` when reviewed groups are hidden. Near-miss runs set `stats.near_candidates_skipped` if bounded-work limits skip candidate comparisons, which means the near-miss result may be incomplete.

## Clone families

Clone groups sharing the same file set are grouped into **clone families** with refactoring suggestions:

* **Extract function**: clones are in the same file
* **Extract module**: clones span multiple files

## Cross-language detection

Compare TypeScript and JavaScript files by stripping type annotations:

```bash theme={null}
fallow dupes --cross-language
```

Fallow normalizes `.ts` files to their `.js` equivalent for comparison. This catches clones where one copy was converted from TypeScript to JavaScript or vice versa.

## Ignoring imports

Files with the same module wiring are a structural property of well-formatted code, not copy-paste, so that wiring is stripped from the token stream by default. This covers ES imports, re-export declarations, and top-level static `require()` binding declarations.

To count module wiring as clone candidates again, opt out on the command line:

```bash theme={null}
fallow dupes --no-ignore-imports
```

Or set it permanently in config:

```jsonc theme={null}
{
  "duplicates": {
    "ignoreImports": false
  }
}
```

Runtime code, local exports, side-effect `require()` calls, nested `require()` calls, dynamic require arguments, and mixed declarations are still counted.

## Incremental analysis

Only check duplication in files changed since a git ref:

```bash theme={null}
fallow dupes --changed-since main
```

Useful in CI to only report new duplication introduced in a pull request.

## Baseline comparison

Adopt duplication limits incrementally:

```bash theme={null}
# Save current duplication as baseline
fallow dupes --save-baseline fallow-baselines/dupes.json

# Fail only on new duplication
fallow dupes --baseline fallow-baselines/dupes.json
```

## Debugging

Trace all clones of a specific code location:

```bash theme={null}
fallow dupes --trace src/utils.ts:42
```

## Benchmarks vs jscpd

Cold runs (no cache) so each tool works from scratch. Fastest tool per row in bold.

| Project                                               |  Files | fallow |     jscpd |      Faster |
| :---------------------------------------------------- | -----: | -----: | --------: | ----------: |
| [astro](https://github.com/withastro/astro)           |  2,859 |  549ms | **189ms** |  jscpd 2.9x |
| [fastify](https://github.com/fastify/fastify)         |    286 |   90ms |  **64ms** |  jscpd 1.4x |
| [next.js](https://github.com/vercel/next.js)          | 20,552 | 12.66s | **861ms** | jscpd 14.7x |
| [preact](https://github.com/preactjs/preact)          |    244 |   58ms |  **49ms** |  jscpd 1.2x |
| [TanStack/query](https://github.com/TanStack/query)   |    901 |  133ms |  **96ms** |  jscpd 1.4x |
| [svelte](https://github.com/sveltejs/svelte)          |  3,337 |  317ms | **172ms** |  jscpd 1.8x |
| [TypeScript](https://github.com/microsoft/TypeScript) | 38,146 | 13.45s | **4.58s** |  jscpd 2.9x |
| [vite](https://github.com/vitejs/vite)                |  1,420 |  174ms |  **74ms** |  jscpd 2.3x |
| [vue/core](https://github.com/vuejs/core)             |    522 |  109ms |  **78ms** |  jscpd 1.4x |
| [zod](https://github.com/colinhacks/zod)              |    174 |   54ms |  **53ms** |  jscpd 1.0x |

jscpd's Rust rewrite (v5) is faster than fallow for raw duplication scanning across these projects. Fallow's advantage is running duplication inside the same single audit pass as dead code, dependency, complexity, CSS, framework, and security checks, not raw scan speed.

Fallow uses a <Tooltip tip="A sorted array of all suffixes of a string, enabling efficient pattern matching without pairwise comparison">suffix array</Tooltip> with <Tooltip tip="Longest Common Prefix array, used alongside suffix arrays to find the longest shared sequences between code blocks">LCP</Tooltip> for clone detection, avoiding quadratic pairwise comparison.

## See also

<CardGroup cols={3}>
  <Card title="CLI: dupes" icon="terminal" href="/cli/dupes">
    Full reference for the `fallow dupes` command and its flags.
  </Card>

  <Card title="Configuration" icon="gear" href="/configuration/overview">
    Set default duplication thresholds and modes in your config file.
  </Card>

  <Card title="Semantic similar code" icon="code-compare" href="/analysis/similar-code">
    Find differently written functions that may share intent.
  </Card>
</CardGroup>
