CLI tool
istanbuljs/nyc avatar
istanbuljs/nyc

nyc: the Istanbul command line interface for JavaScript coverage

the Istanbul command line interface

5,759 stars362 forksJavaScriptISC

At a glance

What is it?
nyc wraps a test command, instruments the source files your tests require, and writes coverage reports. It is aimed at teams whose test runner does not already ship IstanbulJS, and it is not the right tool if you use jest or tap.
Who is it for?
Adopt nyc when your test runner is mocha, AVA or another framework that does not bundle the IstanbulJS libraries, and when your tests spawn subprocesses or run through Babel or TypeScript source maps. Do not adopt it if you already use jest or tap, since the README states those runners provide coverage themselves.
Can I use it commercially?
Yes. ISC is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 135 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap nyc fills between a test runner and a coverage report

Most JavaScript test runners execute code and report pass or fail. They do not tell you which lines the suite never reached. nyc is the command line client for Istanbul, and its job is to sit between your test command and your source files, counting what runs. The README describes it as "Istanbul's state of the art command line interface" with two specific areas of support: applications that spawn subprocesses, and source mapped coverage of Babel and TypeScript projects. Those two clauses matter more than the general pitch. Subprocess support means a test that launches a child process still contributes coverage, which is where naive instrumentation usually loses data. Source map support means the report points at your original .ts or pre-Babel .js lines rather than at compiled output. The audience is narrow and clear: teams on mocha, AVA, tap, or a custom runner, whose tests are real processes rather than in-process function calls. If your runner already bundles the IstanbulJS libraries, nyc adds a second layer of the same machinery.

How the require hook instruments code at runtime

The mechanism is a require hook, not a build step. The README is explicit: by default nyc only collects coverage for source files visited during a test, and it does this "by watching for files that are `require()`'d during the test". When a file is required, nyc returns an instrumented version of the source instead of the original. Instrumentation means line counters are inserted into the code, so each executed line increments something the reporter can read later. Raw coverage data lands in the temp directory, which defaults to `./.nyc_output`, and the report command turns that into human-readable output in `./coverage`. Two consequences follow from the hook design. First, files that are never required never appear in the report unless you set `all` to true, which is why the default report can look flattering on a codebase with untested modules. Second, because instrumentation happens at require time, the hook has to coexist with other loaders such as Babel and TypeScript, which is exactly why the project ships separate shared config packages for those setups rather than one universal preset.

Installing nyc and running your first coverage report

Install it as a development dependency with your package manager. The README gives `npm i -D nyc` or `yarn add -D nyc`.

bash
npm i -D nyc

The documented pattern is to add a coverage script that calls your existing test script through nyc, rather than editing the test script itself. The README shows this package.json shape, with mocha standing in for whatever runner you use.

json
{
  "scripts": {
    "test": "mocha",
    "coverage": "nyc npm run test"
  }
}

Running `npm run coverage` executes your suite under the require hook and writes a text report to the terminal by default, since `reporter` defaults to `['text']`. To get an HTML and lcov report instead, pass reporters on the command line before the program name, as the README does here.

shell
nyc --reporter=lcov --reporter=text-summary ava

Order matters: configuration arguments must come before the program nyc executes. The output of the first example is a per-file text table; the second writes `lcov.info` plus an HTML report into `./coverage` and prints a summary to stdout. If you would rather not add the dependency, the README notes you can run `npx nyc@latest mocha`, and warns that this may pull updates you are not ready for, so it suggests pinning a major version such as `nyc@14`.

Configuration files, extends, and the TypeScript and Babel presets

nyc accepts any command line option through a config file. The README lists `.nycrc`, `.nycrc.json`, `.nycrc.yaml`, `.nycrc.yml`, `nyc.config.js`, `nyc.config.cjs` and `nyc.config.mjs`, plus an `nyc` stanza in package.json. The `.js` and `.mjs` variants exist for cases where logic is needed, and the README's own example computes a platform-specific exclude list using `is-windows` and the `@istanbuljs/schema/default-exclude` module. For TypeScript and Babel the project does not expect you to assemble the settings yourself. It points at `@istanbuljs/nyc-config-typescript` and `@istanbuljs/nyc-config-babel` as starting points, pulled in through the `extends` key. A minimal TypeScript config looks like this, taken from the README.

json
{
  "extends": "@istanbuljs/nyc-config-typescript",
  "all": true,
  "check-coverage": true
}

The `all` and `check-coverage` keys are the two defaults most teams change. `all` is false by default, meaning only files touched by the suite are instrumented; setting it true instruments everything matched by `include`. `check-coverage` is false by default and, when enabled, fails the run if coverage falls outside your thresholds. Both are documented in the options table alongside `extension`, whose default list already covers `.js`, `.cjs`, `.mjs`, `.ts`, `.tsx` and `.jsx`, and `report-dir`, which defaults to `./coverage`.

Where nyc gets in the way

The require hook is the source of most friction. Because instrumentation happens when a module is loaded, anything that bypasses the normal module system, such as code evaluated through a custom loader or a bundler that pre-compiles everything before the test process starts, can escape the hook entirely. The README's own remedy for one such case is a separate shared config, `@istanbuljs/nyc-config-hook-run-in-this-context`, which tells you the problem is real enough to have a package named after it. The second limitation is the default reporting scope. With `all` set to false, a module that no test imports is simply absent from the report, so a project can show high percentages while large parts of its source are never instrumented at all. Turning `all` on changes the numbers, often downward, and can surface files that the default exclude list would have skipped anyway. Third, `check-coverage` is a binary gate on thresholds you choose; it does not distinguish a genuinely untested branch from a defensive one that cannot be reached, so a strict threshold on a codebase with platform-specific files tends to produce either permanently ignored files or a permanently failing build. Finally, the README states plainly that if you use jest or tap you do not need nyc, because those runners already include the IstanbulJS libraries. Installing it there adds an instrumentation layer that duplicates work the runner is already doing.

nyc against c8, and what the difference means in practice

The most direct alternative is c8, which the README itself links to in its CI badge URL. The two take opposite approaches to the same problem. nyc instruments source code before it runs, rewriting modules as they are required so that counters are embedded in the executed program. c8 relies on V8's built-in coverage, collecting what the engine records during execution and mapping it back with source maps. That difference decides several things. c8 does not need to interpose on the module loader, so bundlers and unusual loaders are less of an obstacle; nyc's hook is more sensitive to how modules are loaded. In exchange, nyc's instrumentation is explicit and its output passes through the Istanbul reporting stack, which is what the large ecosystem of Istanbul reporters and shared configs is built around. If your project already extends `@istanbuljs/nyc-config-typescript` or publishes a shared config as an npm module, moving to c8 means rebuilding that configuration. If your tests spawn subprocesses, nyc documents support for that case directly, which is the scenario where the instrumentation approach has historically been the safer bet. The honest summary is that c8 is the lighter mechanism and nyc is the one with the established configuration ecosystem.

Maintenance, licence, and the cost of staying current

The repository is not archived and the last push was on 2026-05-17. Release history is uneven: nyc-v17.0.0 landed on 2024-06-09, nyc-v17.1.0 on 2024-09-19, and nyc-v18.0.0 on 2026-02-22. That is a gap of roughly seventeen months between the 17.1.0 and 18.0.0 releases, which is worth knowing if you plan to track majors closely. The package is published under the ISC licence, a permissive licence that permits use and redistribution provided the copyright notice and permission notice are retained; the repository carries the text in LICENSE.txt. As with any dependency, whether that fits your organisation's policy is a question for your own review, not something the project decides for you. Upgrade cost is mostly concentrated in major versions. The README's own advice about npx is instructive here: it warns that `npx nyc@latest` may give you updates you are not ready for and suggests pinning a major version instead. For a tool that hooks the module loader, a major bump is the release most likely to change instrumentation behaviour, so pinning and reading the changelog before moving is the cheaper path.

Editorial conclusion

Adopt nyc when your test runner is mocha, AVA or another framework that does not bundle the IstanbulJS libraries, and when your tests spawn subprocesses or run through Babel or TypeScript source maps. Do not adopt it if you already use jest or tap, since the README states those runners provide coverage themselves. Before wiring it into CI, verify three things: that your `exclude` list is not hiding files you care about, that `all` is set if you want untested files counted, and that `check-coverage` thresholds match what your current suite actually reaches.

Frequently asked questions

Do I need to install nyc if I already use jest or tap?

No. The README states that if you use jest or tap you do not need to install nyc, because those runners already have the IstanbulJS libraries and provide coverage themselves. Follow their documentation to enable coverage reporting instead.

How do I install nyc?

Add it as a development dependency with `npm i -D nyc` or `yarn add -D nyc`. You can also run it without installing by using `npx nyc@latest`, though the README warns this may pull updates you are not ready for and suggests pinning a major version.

Which config files does nyc read?

Options can go in the `nyc` stanza of package.json or in `.nycrc`, `.nycrc.json`, `.nycrc.yaml`, `.nycrc.yml`, `nyc.config.js`, `nyc.config.cjs` or `nyc.config.mjs`. The JavaScript variants are for cases where programmed logic is required.

How do I set up nyc for a TypeScript project?

The README says to start with the pre-configured `@istanbuljs/nyc-config-typescript` preset and reference it through the `extends` key in your config. You then add your own options, such as `all` or `check-coverage`, alongside it.

Why does my coverage report only show some of my files?

By default nyc only collects coverage for source files visited during a test, by watching for files that are `require()`'d. Files no test imports are absent from the report unless you set `all` to true, which instruments everything matched by `include`.

Official sources

  1. istanbuljs/nyc on GitHub
  2. License: ISC
  3. Project website
  4. README
  5. Releases
For maintainers

Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/istanbuljs-nyc.svg)](https://hysenlabs.com/projects/istanbuljs-nyc)
Community notes

Community notes