babel-plugin-istanbul: coverage instrumentation as a build step
A babel plugin that adds istanbul instrumentation to ES6 code
At a glance
- What is it?
- babel-plugin-istanbul is a Babel plugin that rewrites your source with Istanbul coverage counters and does nothing else. It produces no report and writes no data file, which is what makes it usable with karma-coverage and with mocha through nyc, since each of those does its own reporting. The configuration lives in two places, the Babel config for the plugin options and the package manifest for the nyc rules.
- Who is it for?
- babel-plugin-istanbul fits a project that transpiles with Babel anyway and wants coverage that follows the same transform pipeline as the code under test, so that a file that is transpiled in the test run is instrumented in the same run. It does not fit a project that does not use Babel, and it does not fit a setup that already instruments through another route.
- Can I use it commercially?
- Yes. BSD-3-Clause 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 95 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 October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A plugin that only instruments
babel-plugin-istanbul adds Istanbul coverage instrumentation to your code, and the note near the top of the readme is the part to read first: this plugin does not generate any report and does not save any data to any file. It only adds instrumenting code to your JavaScript source.
That is a smaller promise than most coverage tooling makes, and it is exactly why the plugin is reusable. The reporting and the data collection belong to whatever is running the tests, and the readme points at the integrations section for how to wire them together.
Two integrations are named in the opening paragraph. It can be used directly with karma-coverage, and with mocha on Node through nyc.
The credits section says the approach was inspired by the original coverage plugin by the author of this one, so the lineage is short and direct rather than inherited from a wider family.
The project is BSD-3-Clause licensed, the last push was on 2026-07-20, and the three most recent releases are all from a single day in September 2025, with the 8.0 line at 8.0.2. The package is published to npm, and the enterprise edition of the package is offered through a subscription service that funds the maintenance of open source dependencies.
Installing it, and the test environment block
The install is a development dependency, because instrumentation belongs in the test pipeline and not in what you ship.
npm install --save-dev babel-plugin-istanbulThen the plugin goes into the Babel configuration, in the test environment block rather than at the top level, which is the detail that makes it safe to have installed.
{
"env": {
"test": {
"plugins": [ "istanbul" ]
}
}
}Because the plugin is registered only in the test environment, a production build does not carry the counters, and the instrumented output never reaches a deployed bundle. The alternative to the environment block is setting the environment variable, and the readme mentions the cross-env package for exactly that on platforms where the syntax differs.
{
"scripts": {
"test": "cross-env NODE_ENV=test nyc --reporter=lcov --reporter=text mocha test/*.js"
}
}That script sets the environment variable, runs nyc with two reporters, one for the machine readable lcov output and one for the summary in the terminal, and then runs the mocha tests over the files in the test directory.
So the arrangement is: the environment variable selects the Babel test environment, the Babel test environment adds the plugin, the plugin instruments, nyc collects, and the reporters write the report.
The karma integration, and the preprocessor you must not add
The karma section is short and contains one instruction that is worth following exactly, because the obvious thing to do is the wrong thing.
The code has to be transpiled by Babel before karma sees it, and the readme names the three usual ways of doing that: the karma babel preprocessor, karma webpack, or karma browserify. After that, you set up karma-coverage as its documentation says, and then the instruction: do not add the coverage preprocessor. This plugin has already instrumented your code, and karma should pick it up automatically.
Adding the coverage preprocessor as well is the mistake, and the reason is that the coverage preprocessor instruments too. You would end up with two layers of counters, and the numbers would not describe the code.
The section also notes the scale at which it has been exercised, with a reference to a project of about 2400 statements, which is a useful data point because the cost of instrumenting is proportional to the size of the source and 2400 statements is where that cost starts to be noticeable.
The phrase used for the integration is that it just works, and the mechanism behind that is the same one as the karma instruction: because the instrumentation happens in the Babel transform that karma already uses, there is nothing extra to configure beyond the one thing you must not configure.
The nyc integration, and the double instrumentation to avoid
For mocha on Node, the arrangement goes through nyc, and the readme splits the setup into two halves that have to be done together.
First, configure mocha to transpile your JavaScript with Babel. Then run the tests with nyc, which collects the coverage report.
The plugin respects the include and exclude configuration options from nyc, which is convenient. But the second half is the part that is easy to miss: you also need to configure nyc not to instrument your code, and the settings go in the package manifest.
"nyc": {
"sourceMap": false,
"instrument": false
},The instrument flag turned off is the whole point. nyc instruments by default, and if it does that as well as the plugin, every line is counted twice and the coverage report describes a program that does not exist.
The source map flag is the other half, and it is not a contradiction of the plugin's own source map handling. The plugin attaches source maps so that the coverage can be remapped back to the original source, while the source map setting in the nyc block is about nyc's own source map handling, which would otherwise apply a second transformation to the maps the plugin has already attached.
The result is a split responsibility: the plugin does the instrumenting and the mapping, nyc does the collecting and the reporting, and each is told to stay out of the other's way.
Excluding test files, and the source map options
The excluding section addresses a mistake that every project makes once. You do not want to cover your test files, because that skews the results, and the fix is to give the plugin options that match the nyc exclude and include rules.
{
"env": {
"test": {
"plugins": [
["istanbul", {
"exclude": [
"**/*.spec.js"
]
}]
]
}
}
}And there is a convenience for the case where you would rather not repeat the rules: if you do not provide options in the Babel configuration, the plugin will look for the exclude and include configuration under an nyc key in the package manifest. So the same rules can live in one place and be used by both tools.
The section also points at the ignore hints that Istanbul provides for skipping individual lines, which is the escape hatch for a line that cannot be covered, such as a deliberate error branch.
The source map section describes the default behaviour: the plugin picks up inline source maps and attaches them to the instrumented code so that coverage can be remapped back to the original source, and it notes that this works even for multi step build processes. The catch is that it can be memory intensive, and the option to prevent it is a single flag.
{
"env": {
"test": {
"plugins": [
["istanbul", {
"useInlineSourceMaps": false
}]
]
}
}
}There is also a programmatic path, for a project that does its own transformation, and it takes the source map as an explicit input rather than picking it up from the file.
import babelPluginIstanbul from 'babel-plugin-istanbul';
function instrument(sourceCode, sourceMap, filename) {
return babel.transform(sourceCode, {
filename,
plugins: [
[babelPluginIstanbul, {
inputSourceMap: sourceMap
}]
]
})
}The package layout and the test suite
The repository is small, and the manifest is the clearest description of what the project does.
The runtime dependencies are five, and each is a distinct piece of the job. The Babel helper for plugin utilities handles the plugin plumbing, the nyc configuration loader is what reads the rules from the package manifest when the Babel config does not override them, a schema package validates those options, the instrumentation library is the part that actually rewrites the code, and the file exclusion library decides what to leave alone.
The published package contains only the built library directory, and the build is a single Babel invocation from the source directory into the output directory. The development dependencies are the Babel toolchain, mocha, nyc, chai, and the standard linter.
Two details in the manifest are about the tests rather than the plugin. The standard linter is configured to ignore the fixtures directory, because the fixture files are deliberately badly formatted or deliberately unusual, and the nyc configuration in the manifest includes the fixtures alongside the source. There is a fixture file whose name says it is supposed to be covered, and the exclusion rules are set so that the fixture is measured, which is how the exclusion logic itself is tested.
The test command runs the linter, then the build, then nyc with mocha and a timeout of five seconds over the test directory, and the coverage script pipes the text lcov report into the coveralls service. The publishing step runs the tests and the build before the package goes out, which is the arrangement that keeps a broken build from being published.
There is also a workspace entry for a Babel 8 test, which suggests the project is already checking itself against the next major version of the compiler while shipping against the current one.
Editorial conclusion
babel-plugin-istanbul fits a project that transpiles with Babel anyway and wants coverage that follows the same transform pipeline as the code under test, so that a file that is transpiled in the test run is instrumented in the same run. It does not fit a project that does not use Babel, and it does not fit a setup that already instruments through another route. Verify first that the two instrumenters are not both active, because the plugin and nyc will each instrument the code and the counters will be wrong, that the test files are excluded so the numbers describe the code rather than the suite, and that the source map setting matches your build, since the default of inline source maps is convenient and expensive.
Frequently asked questions
What does babel-plugin-istanbul do?
It is a Babel plugin that adds Istanbul coverage instrumentation to your JavaScript source. It deliberately does not generate a report or save any data, it only rewrites the code, so that the reporting is left to karma-coverage or to nyc.
How do I install and configure babel-plugin-istanbul?
Install it as a development dependency, then add the plugin name to the plugins list in the test environment block of your Babel configuration, so that production builds are not instrumented. You can also set the environment variable to the test value with the cross-env package if you prefer to select the environment that way.
Why should I not add the coverage preprocessor to karma?
Because this plugin has already instrumented the code, and the coverage preprocessor would instrument it a second time, so the counters would not describe the code. The karma integration needs the code transpiled with Babel first, through the karma babel preprocessor, karma webpack, or karma browserify, and then karma-coverage set up on its own.
How do I stop nyc and babel-plugin-istanbul from instrumenting twice?
The plugin respects the include and exclude rules from nyc, but you also have to tell nyc not to instrument your code, by setting the instrument option to false and the source map option to false in the nyc block of your package manifest.
How do I exclude my test files from coverage with babel-plugin-istanbul?
Give the plugin options that match the nyc exclude and include rules, for example an exclude entry for the spec files. If you do not provide options in the Babel configuration, the plugin looks for the exclude and include configuration under an nyc key in the package manifest, so the same rules can be shared with nyc.
Official sources
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.
[](https://hysenlabs.com/projects/istanbuljs-babel-plugin-istanbul)