Repository navigation
Description
Clear and concise description of the problem
In our project, we have a need to use isolate: false and fileParallelism: false in vitest.
We have seen that under this configuration, the number of vitest mocks being kept in memory grows as your test suite runs. This is not surprising given the shared context.
What is surprising, is there is no clear mechanism to control this.
The result is that calling functions like clearAllMocks or restoreAllMocks get progressively slower over time (as we simply loop over all active mocks) - without ever having a way to reduce the size of the set.
I have 5 test files, that each create a large number of mocks and you can see the performance of clearAllMocks degrades over time - relative to the number of mocks being created.
This is an extreme case (with 1000's of mocks created) - but in our real-world case, we aren't mocking many functions - but having a lot of tests (5000+ tests) & even mocking a reasonable number of functions per test, get's out of control quickly.
Using isolate: true, does solve this problem - because the context is reset between tests. But this introduces other problems we then have to overcome.
Suggested solution
I find it surprising there is no way to "clean/kill mocks" that are in memory.
We have the power to clean up other parts of shared context unstubAllGlobals or unstubAllEnvs are maybe good examples?
I'd kind of expect some killAllMocks function.
Alternative
I guess there is an argument that we should mock less things. Or not run with isolate: false.
But if we imagine for a second, that there is a use case for mocking a large number of functions in a shared context (we have one in our project) - there is not equal alternative.
Alternatively I guess we could also say that resetAllMocks or restoreAllMocks should be keeping this list under control itself. I don't see any reason that we would want to just let this set grow forever as my tests run.
Additional context
I'd be open to a suggestion on how to solve this problem with existing methods - without resorting to:
- Changing
isolate:falseorfileParallelism: false - Mocking less things
Validations
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
Activity
Stop re-importing one app graph 253 times, and stop replaying it on P…
MikeDabrowski commentedon Aug 26, 2026
We're seeing what looks like the same underlying pattern, though triggered by test fixtures rather than
vi.fnmocks specifically — worth noting in case it points to a broader "nothing gets released underisolate: false" issue rather than something mock-registry-specific.Our setup: Angular + Vitest, ~8500 tests across ~970 files,
pool: 'threads'/'vmThreads',isolate: false,restoreMocks: true,mockReset: true(for the same reason — perf, at this test countisolate: trueis too slow to be usable in CI).Running with
logHeapUsage: true,process.memoryUsage().heapUsedclimbs steadily for the whole run rather than staying flat between files:Of ~3580 consecutive test-to-test deltas, 2259 were increases vs. 783 decreases — so growth dominates, but it's not that GC never runs: the 10 largest single-step drops (600–1200 MB each) all cluster very late in the run, once heap pressure is already high, suggesting GC is deferred rather than truly blocked. That's consistent with some memory (real garbage) eventually getting reclaimed while another category (retained by Vitest itself, e.g. the mock registry this issue describes, but possibly also fixtures/DI graphs) never does.
Switching to
isolate: truedoes stop the growth for us too, but became impractical at this scale — a partial run at ~1/5 the speed ofisolate: falsebefore we gave up.Given
clearAllMocks/restoreAllMocks/resetAllMocksare already the documented way to reset state between tests, it'd be a meaningful win if they (or a new explicit API, as suggested above) could also drop the retained references so long suites don't have to choose between speed (isolate: false) and bounded memory.sdjayna commentedon Sep 13, 2026
A data point on why this matters beyond memory, and a cross-reference. The registry walk that #11092 removes got about twice as slow per step on Node 26.4.0 and later, so suites running with
isolate: falseandclearMocks: trueon Node 26 doubled in wall time compared with Node 24 (one 174-file Angular suite: about 7 minutes to about 20 on CI). The cause is a V8 cache collision thatvi.fn()triggers exactly:Object.defineProperty(mock, "length", ...)normalizes the function, the state object literal with itslastCallgetter is normalized too, and on Node 26.4+ the two evict each other from V8'sNormalizedMapCacheon every mock, so every store inmockClearmisses.Bisected and reported upstream with a 16-line repro: nodejs/node#66011, V8 https://issues.chromium.org/issues/560730175, fix https://chromium-review.googlesource.com/c/v8/v8/+/8397811. For anyone on Vitest 4 who cannot upgrade yet, applying the 27-line change from #11092 to
@vitest/spy4.1.11 as a package patch takes the same suite from 8 minutes to 1 min 20 s on Node 26.8.[objects] Hash the instance type into the NormalizedMapCache index