ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 21

  1. Blog

c8 vs nyc: Should You Switch? 4.2s vs 7.4s

c8 12.0.0 vs nyc 18.0.0 on 80 CommonJS modules / 480 mocha tests: coverage-run median 4222 ms vs 7415 ms (~1.76x; no-coverage baseline 1734 ms). Same code, different totals: branches 81.3% (c8) vs 47.9% (nyc).

Aditya Challa·5 October 2026·5 min read

Hands-on
On this page
  1. What I tested
  2. Is c8 faster than nyc?
  3. Why do c8 and nyc report different coverage?
  4. Should you switch from nyc to c8?
  5. Sources
  6. Related

On 80 CommonJS modules with 480 mocha tests, c8 12.0 finished a full coverage run in a median 4.2 s and nyc 18.0 took 7.4 s (~1.76x slower), against 1.7 s with no coverage at all. The two tools also disagreed on the numbers: c8 reported 81.3% branches and 63.3% lines, nyc reported 47.9% branches and 58.5% lines for the same run.

Short answer: switch to c8 if your tests run on plain Node and you want lower coverage overhead with no instrumentation step. Stay on nyc if you rely on Babel-instrumented code, Istanbul-specific ignore hints, or coverage thresholds you cannot re-baseline this sprint. No affiliate links in this post.

What I tested

  • Machine: 8 vCPU Intel Xeon / 15 GB RAM Linux cloud box, Node 20.19.2, tested 5 Oct 2026 (about 23:13 to 23:15 IST). Shared box; variants interleaved each round.
  • Fixture: 80 CommonJS files under src/ (7,280 lines, 8 functions each with if/else-if/else loops, plus one never-called function per file) and 80 mocha test files (480 tests). Generator script kept with the raw results.
  • Tools: c8 12.0.0, nyc 18.0.0, mocha 12.0.3. Same config for both: include every .js file under src/, all: true, reporters text-summary and lcov.
  • Timing: one nyc warmup to fill its cache, then five interleaved rounds of four variants: plain mocha, c8 mocha, nyc mocha (default cache on), nyc --cache=false mocha. Coverage folders deleted before every run. Wall clock via process.hrtime around the full npx command.
  • Findings: medians 1733.9 ms (no coverage), 4221.8 ms (c8), 7414.5 ms (nyc, cache on), 8677.9 ms (nyc, cache off). c8 runs 4135 to 4359 ms; nyc cache-on runs 7323 to 8167 ms.
  • One surprise: the coverage percentages are not comparable. c8 counted 7,280 lines and 3,251 branches; nyc counted 5,280 lines and 5,280 branches on identical code. Any CI threshold tuned on nyc will move when you switch.
  • Not tested: TypeScript or ESM sources, Babel-instrumented builds, Jest or Vitest coverage providers, the --experimental-monocart flag, Windows/macOS, suites above a few thousand tests.

Is c8 faster than nyc?

VariantMedian wallRuns (ms)Overhead vs no coverage
mocha, no coverage1734 ms1734 / 1665 / 1665 / 1816 / 1759none
c8 12.04222 ms4359 / 4177 / 4135 / 4222 / 4340+2488 ms (2.4x)
nyc 18.0, cache on7415 ms7997 / 7415 / 8167 / 7323 / 7386+5681 ms (4.3x)
nyc 18.0, cache off8678 ms8678 / 9065 / 8562 / 8766 / 8452+6944 ms (5.0x)

Yes, on this fixture. c8 reads coverage that V8 already collects while the code runs, so there is no source rewrite before tests start. nyc rewrites every included file with Istanbul counters first, and the counters also slow down hot loops like the ones in this fixture. Its cache only removed about 1.3 s of the cost.

Test-runner choice is a separate decision. The Jest vs Vitest post and the Vitest 5 upgrade post cover the runner itself; this post only covers coverage for a mocha or plain Node suite. If you also need a DOM, the jsdom vs happy-dom post has those numbers.

Why do c8 and nyc report different coverage?

Metricc8 12.0nyc 18.0
Statements63.31% (4609/7280)57.97% (5009/8640)
Branches81.26% (2642/3251)47.89% (2529/5280)
Functions66.66% (480/720)66.66% (480/720)
Lines63.31% (4609/7280)58.50% (3089/5280)

c8 converts V8 byte ranges to lines, so every physical line counts, including closing braces. nyc counts the statements and branch paths Istanbul inserted at instrumentation time. Function coverage matched exactly at 480 of 720. Branch coverage moved the most, by 33 points. Plan to reset your thresholds the day you switch, and compare per-file reports before trusting the new totals.

Disk use also differed. c8 left 3.9 MB in coverage/ (the lcov report plus raw V8 JSON in coverage/tmp). nyc left 1.6 MB in coverage/ plus 2.8 MB in .nyc_output/. Both lcov.info files were about 150 to 160 KB.

Should you switch from nyc to c8?

SituationMy pick
Plain Node or mocha suite, CI time mattersSwitch to c8; re-measure on your suite
Coverage gate in CI tuned to nyc numbersSwitch only with a planned threshold reset
Code is instrumented through Babel (babel-plugin-istanbul)Stay on nyc
You depend on /* istanbul ignore */ hints everywhereTest c8 first; it supports c8 ignore hints instead
Tests already run in Vitest or JestUse that runner's coverage provider, not either CLI

Bottom line: on 480 mocha tests, c8 added about 2.5 s of coverage cost and nyc added about 5.7 s, so c8 was roughly 1.76x faster end to end. Who should not switch yet: teams whose release gate depends on today's nyc percentages and who cannot re-baseline. For a Node runtime choice on the same box, see the tsx vs ts-node post.

How this was made: I generated the fixture, ran the interleaved coverage runs on the ShopperCove test box, and kept the timing JSON; the write-up was drafted with AI help and checked against that output.

Sources

  • https://github.com/bcoe/c8
  • https://github.com/istanbuljs/nyc
  • https://nodejs.org/api/cli.html#node_v8_coveragedir
  • https://www.npmjs.com/package/c8
  • https://www.npmjs.com/package/nyc
  • https://mochajs.org/

Related

  • https://www.shoppercove.com/blog/jest-vs-vitest
  • https://www.shoppercove.com/blog/vitest-5-should-you-upgrade-october-2026
  • https://www.shoppercove.com/blog/jsdom-vs-happy-dom-vitest
  • https://www.shoppercove.com/blog/tsx-vs-ts-node
  • https://www.shoppercove.com/blog/playwright-1-63-test-locks-october-2026
  • https://www.shoppercove.com/blog/knip-vs-depcheck
  • https://www.shoppercove.com/blog/oxlint-vs-eslint
  • https://www.shoppercove.com/blog/nodejs-26-lts-october-2026-schedule-change
c8nycnode.jscode coveragemochabenchmarkstesting

Lab evidence

What I found running this

Hands-on on ShopperCove box 5 Oct 2026 ~23:13-23:15 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 20.19.2). Fixture: 80 CJS modules in src/ (7,280 lines, 8 branchy functions + 1 unused each), 80 mocha test files / 480 tests. Versions: c8 12.0.0, nyc 18.0.0, mocha 12.0.3; same include src/*.js, all:true, reporters text-summary+lcov. 1 nyc cache warmup, then 5 interleaved rounds, coverage dirs deleted each run. Medians: no coverage 1733.9 ms (1733.9/1664.6/1664.8/1816/1758.9); c8 4221.8 ms (4359.2/4176.7/4135.4/4221.8/4340.1); nyc cache-on 7414.5 ms (7997/7414.5/8167.1/7323.3/7385.9); nyc --cache=false 8677.9 ms (8677.9/9065/8562/8765.5/8451.5). Coverage: c8 stmts 63.31% (4609/7280), branches 81.26% (2642/3251), funcs 66.66%, lines 63.31%; nyc stmts 57.97% (5009/8640), branches 47.89% (2529/5280), funcs 66.66%, lines 58.5% (3089/5280). Disk: c8 coverage/ 3.9 MB (incl. tmp V8 JSON); nyc coverage/ 1.6 MB + .nyc_output 2.8 MB. Raw: /workspace/bench-c8-nyc/res-c8-nyc.json. Not tested: TS/ESM sources, Babel instrumentation, Jest/Vitest providers, --experimental-monocart, Windows/macOS. No affiliate.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Related links

  • Plate 68

    pnpm vs npm vs Bun: Which Installs Fastest? 14s, 3.1s, 1.5s

    npm 12.2.0 vs pnpm 12.9.1 vs Bun 1.4.2 on one 24-dependency React + Vite app: from scratch 14.2 s / 3.1 s / 1.5 s; lockfile + warm cache 2.9 s / 0.28 s / 0.27 s; lockfile + empty cache 3.9 s / 2.3 s / 0.45 s. Disk, lockfile size and the pnpm phantom-dependency catch.

    5 Oct 2026

  • Plate 04

    Ajv vs Zod: 3.9M vs 1.1M Validations per Second

    ajv 8.20.0 (+ajv-formats 3.0.1) vs zod 4.6.5 on the same nested user shape as zod-vs-valibot. Warm medians (2k warmup + 9x50k): Ajv validate ok 3,933,337 ops/s vs zod.safeParse 1,138,406 (~3.5x). Bad input: Ajv allErrors 4,094,452 vs Zod 435,537 (~9.4x). Setup: Ajv new+addFormats+compile median 6.47 ms vs Zod build 0.17 ms; break-even ~10k validations. Browser gzip: Ajv runtime 41 KB, Ajv standalone 1.8 KB, Zod classic 93 KB, zod/mini 6.8 KB. Fixture /workspace/bench-ajv-zod/.

    5 Oct 2026

  • Plate 12

    Yarn Berry vs pnpm: 1.3s vs 0.24s Install

    Yarn 4.9.2 (Berry PnP + node-modules linker) vs pnpm 12.9.1 on one 22-dependency React+Vite app. Isolated caches (Yarn enableGlobalCache false; pnpm --store-dir). Warm medians (5): Yarn PnP 1.307 s, Yarn nm 2.471 s, pnpm 0.240 s. Lock+empty medians 1.656 / 2.789 / 0.725 s. Clean disk: Yarn PnP 246 MB; Yarn nm modules 189 MB; pnpm hardlink project 167 MB. Fixture /workspace/bench-yarn-pnpm/. Distinct from pnpm-vs-npm-vs-bun (no Yarn).

    5 Oct 2026

On this page

  1. What I tested
  2. Is c8 faster than nyc?
  3. Why do c8 and nyc report different coverage?
  4. Should you switch from nyc to c8?
  5. Sources
  6. Related
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove