Vitest coverage exclude: files, folders and lines
The patterns and comments that work in Vitest 5.1, and five that look right but are not, each one measured.

Put the pattern in test.coverage.exclude, write it from the project root and
end folders with /**: src/generated/**. To ignore lines inside a file, use
a /* v8 ignore */ comment.
Exclude patterns at a glance
| To exclude | Write |
|---|---|
| A folder | coverage.exclude: ['src/generated/**'] |
| A folder name anywhere | coverage.exclude: ['**/generated/**'] |
| One file | coverage.exclude: ['src/legacy/old-pricing.ts'] |
| Files by name | coverage.exclude: ['**/*.config.ts'] |
| From the command line | --coverage.exclude='src/generated/**' |
| The next statement | /* v8 ignore next */ |
An if branch | /* v8 ignore if */ |
| A block of lines | /* v8 ignore start */ … /* v8 ignore stop */ |
Test files never need excluding. Vitest leaves them out of the report, even a
test file inside src that your include pattern matches.
We ran every setup here with Vitest 5.1.0 and Node.js 24. The test project
has four source files. One of them, src/legacy/old-pricing.ts, no test
imports.
Exclude files and folders
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
coverage: {
include: ['src/**/*.ts'],
exclude: ['src/generated/**', 'src/legacy/**'],
},
},
})
The report then listed two files, 9 of 9 lines. Patterns are globs matched against each file’s path from the project root.
include matters as much as exclude. By default Vitest reports only the
files your tests import. Our unimported legacy file was not in the report
until we added include: ['src/**/*.ts']; then it showed at 0 of 1 lines. So
a file you never import is already out of the report, and it appears only
when include brings it in.

Ignore lines with comments
function format(cents: number): string {
/* v8 ignore if */
if (cents < 0) {
return `-${format(-cents)}`
}
return `${Math.floor(cents / 100)}.${String(cents % 100).padStart(2, '0')}`
}
Our receipt.ts has this hint and one /* v8 ignore next */. Without the two
comments it had 3 of 5 lines and 1 of 2 branches; with them, 3 of 3 lines and
no branches left to cover. next skips the next statement, and start /
stop skip everything between them.
The docs suggest -- @preserve, as in /* v8 ignore if -- @preserve */,
because older builds stripped comments from TypeScript. In Vitest 5.1.0 the
hints worked both with and without it.
On the default V8 provider, /* istanbul ignore if */ worked too. On the
Istanbul provider only istanbul hints work: the v8 ignore comments were
ignored and the file went back to 3 of 5 lines.
Why your Vitest coverage exclude isn’t working
| What we tried | What happened |
|---|---|
exclude: ['generated'] | Nothing excluded: the pattern is matched from the root |
exclude: ['src/generated'] or 'src/generated/' | The imported file stayed in the report |
exclude: ['src/legacy'], a folder no test imports | Excluded |
test.exclude instead of test.coverage.exclude | No change: it picks which test files run |
v8 ignore comments with provider: 'istanbul' | Ignored |

The second and third rows disagree. The docs say a pattern without a wildcard
counts as a folder, and that held only for files Vitest found through
include. Files your tests import need the /**. Write it every time.
You may have seen ...coverageConfigDefaults.exclude spread into
exclude. In Vitest 5.1.0 it is an empty list, so it changes nothing.
What Supercov adds
npx supercov -- npx vitest run
npx supercov runs latest gaps
Supercov runs the same command and records which test covered each line,
with branches and MC/DC, without Vitest’s coverage provider. It decides what
counts from your source directories, not from coverage.exclude. See
Vitest coverage: V8 vs Istanbul for how the two
providers compare, and per-test coverage in Vitest.