uvu: a test runner that starts in 72ms and ships four dependencies
uvu is an extremely fast and lightweight test runner for Node.js and the browser
At a glance
- What is it?
- uvu is a Node.js and browser test runner built around individually executable test files. Its README benchmark puts it at 72ms total process time on Node v10, and the package pulls in only dequal, diff, kleur and sade.
- Who is it for?
- Adopt uvu when your suite is plain JavaScript or TypeScript tests that you want to run as individual files, with a runner that adds four dependencies and starts in tens of milliseconds. Skip it if you need watch mode and first-class coverage built into the runner, since the README documents neither and the repository only offers them as examples.
- Can I use it commercially?
- Yes. MIT 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 11 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 3, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What uvu replaces, and for whom
uvu targets the part of testing that most runners treat as fixed cost: process startup, module resolution and a dependency tree that grows with the framework. The README describes it as an extremely fast and lightweight test runner for Node.js and the browser, and the package.json backs that up with four runtime dependencies: dequal for deep equality, diff for output diffs, kleur for terminal colors and sade for CLI parsing. Nothing in that list is a test framework.
The audience is narrower than "everyone writing tests". uvu suits projects that already have a way to run JavaScript and want the test layer to stay thin: a library with a few hundred assertions, a CLI tool, or a component package that runs the same test files in Node and in a browser. It does not suit teams that expect the runner to own coverage, watch mode, reporters and a plugin ecosystem. Those exist in the repository as examples, not as features of the runner itself.
Individually executable test files and thrown-Error detection
The mechanism is unusual and worth understanding before adopting it. A uvu test file imports test from uvu, registers cases with test(name, fn), and then calls test.run() at the bottom of the file. That last call is what actually executes the suite. Because the file is self-running, it works both under the uvu CLI and under node directly, which the README demonstrates as two separate invocation styles.
Failure detection does not depend on an assertion library. The README states that uvu relies on thrown Errors to detect failures, and that any uncaught exception or unhandled Promise rejection results in a failure. That is why the uvu/assert module is described as completely optional and why Node's native assert module works inside a uvu test. The practical consequence: if you throw, you fail, and if you return a rejected promise from an async test, you also fail. There is no separate reporting layer deciding what counts as an error.
The package exposes five entry points through the exports field: the root uvu module, uvu/assert, uvu/diff, uvu/parse and uvu/run. Both CommonJS and ESM builds are published (dist/index.js and dist/index.mjs), with type definitions alongside each.
Installing uvu and running a first test
Install it as a development dependency. The README gives exactly one install command:
npm install --save-dev uvuThen create a test file. The README's own example imports both the runner and the optional assertion module, uses assert.is for strict comparison and assert.snapshot for inline snapshot values, and finishes with test.run():
// tests/demo.js
import { test } from 'uvu';
import * as assert from 'uvu/assert';
test('Math.sqrt()', () => {
assert.is(Math.sqrt(4), 2);
assert.is(Math.sqrt(144), 12);
});
test('JSON', () => {
const input = { foo: 'hello', bar: 'world' };
const output = JSON.stringify(input);
assert.snapshot(output, `{"foo":"hello","bar":"world"}`);
assert.equal(JSON.parse(output), input, 'matches original');
});
test.run();Run it either through the CLI, which picks up files under the directory you pass, or through node for a single file:
uvu -r esm tests
node -r esm tests/demo.jsThe README notes that -r esm is only needed for legacy Node.js versions and links to docs/esm.md for the modern path. With the CLI you should see the registered test names and a pass or fail summary; with node you get the same output for one file, which is the isolation mode the README recommends.
Where uvu stops and you start
The clearest limitation is scope. The README documents installation, the test/suite API, the optional assertion module and a benchmark table. It does not document a watch mode, a coverage reporter, a configuration file or a snapshot update flag. Those capabilities appear in the repository only as directories under examples/, alongside examples/coverage, examples/watch, examples/typescript and examples/puppeteer. An example is a starting point you copy and maintain; it is not a supported feature with a documented interface.
A second constraint is the self-running file model. Every test file must call test.run(). Forget it and the file registers tests and exits silently, which looks like a pass in a CI log that only checks the exit code. That is a real failure mode, and it is the price of the design that makes node tests/demo.js work at all.
Node support is also declared conservatively. The engines field says >=8, and the README's benchmark was run on Node v10.21.0. The -r esm note exists precisely because older versions need a loader. If your project is on a current LTS release, the modern ESM path applies and the flag is unnecessary, but the declared floor tells you the project is not chasing new runtime features.
uvu against Jest and AVA on startup cost
The README publishes a benchmark from the /bench directory, run on Node v10.21.0, listing total process execution time from startup to termination, with self-reported execution time in parentheses where known. The numbers are: ava 594ms, jest 962ms (356ms self-reported), mocha 209ms (4ms), tape 122ms, and uvu 72ms (1.3ms).
The interesting column is the gap between total and self-reported time. Jest reports 356ms of its own execution against 962ms of process time, which means most of the wall clock goes to startup and module loading, not to running assertions. uvu reports 1.3ms against 72ms total. Both runners spend the bulk of their time outside the tests, but the absolute floor differs by roughly an order of magnitude.
That difference is architectural, not a matter of tuning. Jest ships a transform pipeline, a module registry and a worker pool; uvu ships a CLI parser, a small runner and a diff formatter. If your suite runs in seconds, the startup difference is noise. If you run tests on every file save, or in a loop over many small packages, the fixed cost per invocation is what you feel.
Maintenance status, licence and the cost of upgrading
The repository is not archived. The last push was on 2026-09-22, two days before the date of this writing, so the project is receiving commits. That is distinct from releases: the most recent published version is v0.5.6 from 2022-07-03, preceded by v0.5.5 the day before and v0.5.4 on 2022-06-21. Anyone adopting uvu should expect the version they install to be v0.5.6 and should not read the recent commit activity as a signal that a new release is imminent.
The licence is MIT, stated in both the README and package.json. MIT permits commercial and private use with attribution and no warranty, but this is not legal advice; check how your organisation handles third-party notices. The four runtime dependencies each carry their own licences, and the README links to a licenses.dev page for the package.
Upgrade cost is low by construction. The public surface is the test and suite functions, the optional uvu/assert module, and the CLI. The version has sat at 0.5.x since 2022, so there is no migration guide to follow and no major-version churn to absorb. The flip side is that features you want may never arrive in the runner, because the project's answer to coverage and watching is an example directory.
What the browser and TypeScript examples imply
The README lists browser compatibility as a feature and the assertion module as browser compatible, and the examples directory contains preact, solidjs, svelte, puppeteer and two TypeScript variants (examples/typescript and examples/typescript.module). That tells you the intended shape of a browser test: run uvu inside the page or the headless browser, not through a Node-side transform.
The TypeScript situation is the one to check before adopting. There is no documented build step for tests in the README, only example directories. If your test files are TypeScript, you are choosing a loader or bundler yourself and copying the example that matches your setup. That is fine for a team that already owns its build, and friction for a team that expects the runner to compile on the fly.
The same pattern holds for the monorepo and esm.dual examples: they show the runner being pointed at more than one package or at both module formats, but the README does not describe a workspace-aware mode. You are wiring that up.
Editorial conclusion
Adopt uvu when your suite is plain JavaScript or TypeScript tests that you want to run as individual files, with a runner that adds four dependencies and starts in tens of milliseconds. Skip it if you need watch mode and first-class coverage built into the runner, since the README documents neither and the repository only offers them as examples. Before committing, verify the Node version your CI runs against the engines field, which declares >=8, and confirm that your assertion style works with uvu's rule that any thrown Error or unhandled rejection is a failure.
Frequently asked questions
What does uvu mean?
The README expands the name as Ultimate Velocity, Unleashed, which matches the project's emphasis on startup speed and a small dependency footprint.
Who created uvu?
The MIT licence line credits Luke Edwards, and the package.json repository field points at lukeed/uvu on GitHub.
How do I install uvu?
Install it as a development dependency with npm install --save-dev uvu. The package.json also exposes a uvu binary, so the CLI is available to your npm scripts after install.
Can I use Node's built-in assert module with uvu instead of uvu/assert?
Yes. The README states that uvu relies on thrown Errors to detect failures and that the uvu/assert module is completely optional, so Node's native assert works inside a uvu test.
Does uvu include watch mode or coverage reporting?
The README does not document either as a runner feature. The repository includes examples/watch and examples/coverage directories, which are starting points to copy rather than documented options.
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/lukeed-uvu)