StrykerJS: mutation testing for JavaScript and TypeScript
Mutation testing for JavaScript and friends
At a glance
- What is it?
- StrykerJS measures whether a test suite actually detects broken code by mutating your source and re-running the tests. It is aimed at teams whose coverage numbers look healthy but whose assertions do not.
- Who is it for?
- StrykerJS fits teams that already have a passing test suite and want to know which assertions are missing, especially on TypeScript projects where the type checker is part of the signal. It does not fit large untested codebases or anyone expecting a fast, single-number CI gate on the first run, because the default configuration mutates everything under lib and src and re-runs the whole test command per mutant.
- Can I use it commercially?
- Yes. Apache-2.0 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 1 day ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What StrykerJS measures that line coverage does not
A coverage report tells you which lines a test executed. It says nothing about whether the assertion on that line would fail if the line were wrong. StrykerJS attacks that gap directly: it changes your source code in small, deliberate ways and then runs your test suite against the changed code. If the tests still pass, the mutant survived, and the code path it touched is effectively unverified.
The README frames the project as "Mutation testing for JavaScript and friends", and the monorepo is where, in its words, "all official stryker packages are maintained". The audience is anyone with a JavaScript or TypeScript test suite that they trust more than they should. The output is not a percentage of executed lines but a set of concrete surviving mutations, each one a specific edit that your tests failed to notice.
How the mutator, test runner and reporter fit together
The package named in the README is @stryker-mutator/core, and it is the orchestrator. The core package parses your source files, applies mutators to produce mutated copies, and hands each mutant to a test runner plugin. The README points to a list of currently supported mutators on the project website rather than enumerating them in the repository, so the exact operator set is documented there, not in the README text.
Because the runner is a plugin, StrykerJS is not tied to one test framework. The related search terms people use include a Vitest runner and a TypeScript checker, which reflects that both the execution layer and the type-checking layer are separate packages you add next to core. The repository layout supports this: the packages folder is a monorepo managed with pnpm and lerna, so core, runner plugins and checkers ship as distinct npm packages that can be versioned and installed independently.
The data flow is roughly: read the configured source files, generate mutants, run the configured test command once per mutant, collect which mutants were killed, survived, or timed out, and emit a report. That per-mutant execution model is the reason the tool is slow, and it is also the reason its output is trustworthy.
Installing @stryker-mutator/core and running it on a small project
The README gives the install command with pnpm and notes that the bare run form is intended for small projects. Run this from the project root:
pnpm add --save-dev @stryker-mutator/core
# Only for small projects:
npx stryker runThe README states that this runs Stryker with default values: it uses npm test as your test command, and it searches for files to mutate in the lib and src directories. So on a small project with a working npm test script and source under src, the command should start mutating without any config file at all. If your sources live elsewhere, or your test command is not npm test, the defaults will not match and you need configuration instead.
The general invocation form documented in the README takes a command, options and an optional config file:
$ npx stryker <command> [options] [configFile]For anything larger than a toy project, the README redirects to the quickstart and configuration pages on stryker-mutator.io rather than documenting the options inline. That is a deliberate choice and a real friction point: the repository README is a signpost, not a manual.
Why the default run is the wrong first move on a large codebase
Mutation testing costs one test-suite execution per mutant. On a project with a slow integration-heavy test command, the default run over lib and src can take far longer than the test suite itself, and the README's own comment ("Only for small projects") is an admission of that. The tool does not hide this; it just does not solve it for you in the README.
The practical consequence is that StrykerJS is a poor fit as a blocking gate on every pull request for a large repository unless you have narrowed the mutation scope first. It is a good fit as a periodic or targeted analysis. If your test command starts a database, a browser or a container per run, the per-mutant model multiplies that startup cost by the number of mutants, and the run may not finish in a useful window.
A second limitation is configuration surface. The README documents no config keys at all, deferring entirely to the website. Anyone who needs to change the test command, restrict the mutated files, or set a threshold has to leave the repository to find out how. That is a documentation gap, not a capability gap, but it affects how quickly a team can get a meaningful result.
StrykerJS versus plain coverage tooling
The obvious alternative is the coverage tool you already run, such as c8, which appears in the repository's own devDependencies. Coverage instruments execution and reports which statements, branches and functions ran. StrykerJS instruments correctness by changing the code and checking whether the tests object. The difference in approach is the difference between "this line was reached" and "this line is pinned down by an assertion".
A coverage tool is fast because it runs your suite once. StrykerJS is slow because it runs your suite once per mutant. Coverage tells you where to look; mutation testing tells you whether looking was enough. They are complementary, and the repository itself uses c8 for its own coverage while using StrykerJS to check its test quality. If your only goal is a CI badge, coverage is cheaper. If your goal is to find assertions that assert nothing, coverage cannot answer that question at all.
Maintenance, licensing and upgrade cost
The repository is not archived, and the last push was on 2026-09-21, days before this writing. Releases are versioned in the v10 line, with v10.0.0 published on 2026-08-14, following v9.6.1 in April 2026 and v9.6.0 in February 2026. A major version bump means the plugin packages you depend on (the core package plus whichever runner and checker packages you added) need to move together, since they are maintained in one monorepo with a shared release process.
The licence is Apache-2.0. That is a permissive licence with an explicit patent grant, and it does not impose copyleft obligations on your own source. This is a factual note about the licence identifier in the repository, not legal advice; if your organisation has licence policy requirements, route the LICENSE file through whoever handles that.
The upgrade cost is mostly plugin alignment. Because the packages are released from a single monorepo, a core upgrade without matching runner and checker versions is the failure mode to watch for. The repository also carries a CHANGELOG.md at the top level, which is where breaking changes between major versions are recorded.
Editorial conclusion
StrykerJS fits teams that already have a passing test suite and want to know which assertions are missing, especially on TypeScript projects where the type checker is part of the signal. It does not fit large untested codebases or anyone expecting a fast, single-number CI gate on the first run, because the default configuration mutates everything under lib and src and re-runs the whole test command per mutant. Before adopting it, verify the Node version your installed @stryker-mutator/core requires, confirm which test runner package you need alongside core, and check the generated report for any mutants that were never covered at all.
Frequently asked questions
What does Stryker do?
It performs mutation testing on JavaScript and TypeScript: it modifies your source code in small ways and re-runs your tests against each modified version. Mutants that your tests fail to catch indicate assertions that are missing or too weak.
What is StrykerJS?
StrykerJS is the JavaScript and TypeScript mutation testing tool maintained in the stryker-mutator/stryker-js monorepo, where all official Stryker packages live. The core package is @stryker-mutator/core.
What does mutation testing do?
Mutation testing changes your source code deliberately and checks whether your test suite detects the change. A surviving mutant means the tests passed despite broken code, so that part of the code is not actually verified by an assertion.
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/stryker-mutator-stryker-js)