The following is a summary of the Vitest GitHub issue "Vitest runs tests 3x slower than Jest", which if printed would require about 24 pages. So I've summed up all the ideas and advice I found there into a more concise list of things you can try if you notice Vitest being slow. Please note, many performance improvements were merged into Vitest since that issue was created so not all recommendations on this page are still relevant, the goal is just to put them in one spot in a quick, concise, easy to try list.
If you'd like to see some real world benchmarks on a 5.5 year old production app, read my follow up post and what happened when I tried to apply some of these following techniques.
Summary
Things within your control to improve performance:
- Upgrade Node.js. Newer Node versions are faster.
- Switching from
jsdom
tohappy-dom
is faster in most cases, though will require tweaking/adjusting some tests. (some note it is 3x faster to import per test) - Remove or mock heavy dependencies (rather than importing them).
- Rather than import a dependency from a "barrel file", import it from a pre-built file, or directly from the actual file. Example:
- Instead of
import { OneIcon } from 'thousands-of-icons';
doimport OneIcon from 'thousands-of-icons/icons/OneIcon.vue';
. This way you don't have to wait for 2,000+ icon components to be loaded and transformed on every test.
- Instead of
- Read up on deps.experimentalOptimizer and how to adjust your include/exclude/entries settings for better performance in tests and how your dependencies are bundled during test runs.
- Instead of inlining a dependency, alias it to point to a pre-built/CJS version. Example:
environment: 'happydom',
-deps: {
- inline: ['element-plus']
-}
+alias: [
+ {
+ find: /^element-plus$/,
+ replacement: resolve(__dirname, 'node_modules', 'element-plus/dist/index.full.mjs')
+ }
+]
- You can try
--no-threads
CLI argument, depending on your tests this may be much slower or slightly faster. Also some tests may need to be tweaked to work with this. It will usechild_process
instead of worker threads. - The
--single-thread
CLI may also make things much slower or maybe slightly faster depending on the codebase. - Set
css: false
to skip CSS imports in tests (If you are using--browser
then maybe you don't want this, but also--browser
is slower too because... it involves a real browser) - Set
useAtomics: true
to synchronize threads, might improve performance in some repos, but will cause Node to crash in older Node versions. - Increase
concurrent: 5
to a higher value to run more tests simultaneously (maxConcurrency). - Similarly you can increase
minThreads: 8
to set the minimum number of CPU threads that will be used to run tests (also see: maxThreads) - If you opted in to using
--sequence.shuffle
stop using it (or override with--sequence.shuffle=false
). Running tests in a random order is slower because Vitest can cache and sort tests running the slowest ones first which is faster overall. - In some cases the test reporter can be the bottleneck, if you aren't particularly attached to the one you are using you could try a different one to see if performance improves. Example:
vitest --reporter=tap
- If you have any style files that contain
.module
in the file name (ex:sidebar.module.sass
). Follow these instructions - Turning isolation off (
--no-isolate
or--isolate=false
) is 3-8x faster, but will likely break your existing tests, requiring them to be re-written. Also it will cause issues in watch mode. Generally not a good idea. - Adjust the slowTestThreshold to be bigger. If it doesn't report it as being slow, then who's to say it isn't fast? Ride that placebo.
Information:
- You can use the benchmark feature to evaluate where time is spent during test running. Either when running a specific
test()
(asbench()
), or by running--bench
CLI or usingbenchmark: {}
in thetest: {}
config. This can help with debugging slow tests. - There is a
--ui
module graph that may be useful when debugging performance. - Vitest inherits settings from your dev and build Vite config. Some settings will give you better performance once you build your app, but worse performance when running tests, so you need to override these settings in the test config. (I think, this isn't super clear in the docs).
The future
- Vitest relies on the
vm
module. It is being ran in a way that is much slower than how Jest does it. If Vitest were to switch to Jest's approach it would introduce all the bugs Jest has into Vitest. So this will likely never happen as Vitest values correctness over performance (be happy that this is the case). However, oncevm
has proper native ESM support, it will be considerably faster (this is a major bottleneck for Vitest). - If ShadowRealms are ever added to EcmaScript (and implemented into V8/Node) they'll allow for a different approach to isolating code that would be faster without the downsides of sharing
global
.
Be sure to look at the follow up post for real world benchmarks on a 5 year old frontend web app.
Photo Credits:
"Man running along seashore during golden hour" by Swapnil Dwivedi
Top comments (2)
Thank you for this article! Super useful.
Is
minThreads: 8
compatible with--no-threads
? (as I understand it, min-threads is linked to CPU threads, where --no-threads refers to the child process used)This is super helpful! Using this and the tips on performance in this short note, I was able to accelerate Vitest by ~4x for my 800 tests, making it faster than Jest. All I had to do was add the following to my Vitest config: