vitest-dev/vitest · error · Error
vitest/browser can be imported only inside the Browser…
Error message
vitest/browser can be imported only inside the Browser Mode. Your test is running in ${pool} pool. Make sure your regular tests are excluded from the "test.include" glob pattern. What it means
`vitest/browser` is a virtual module resolved only when the test runs under the browser pool (the tester sets globalThis.__vitest_worker__.ctx.pool = 'browser'). The fallback context.js throws on import; if a pool is present but is not 'browser', the message names the offending pool. This prevents accidentally using browser-only APIs (page, userEvent, cdp) in node-run tests.
Solutions
- Narrow the node project's `include` / the browser project's `include` so the same file is not in both.
- Make the `vitest/browser` import lazy/conditional (dynamic import inside a function only called from browser tests).
- Exclude browser specs from the node project's `test.include` (and vice versa) using separate project configs.
- If a third-party dep imports it unconditionally, report upstream or alias the module for non-browser projects.
Example fix
// before - vitest.config.ts single project catches everything
export default defineConfig({ test: { include: ['**/*.test.ts'] } })
// after - split projects by environment
export default defineConfig({
test: {
workspace: [
{ test: { name: 'unit', include: ['test/unit/**/*.test.ts'] } },
{ test: { name: 'browser', include: ['test/browser/**/*.test.ts'], browser: { provider: 'playwright' } } },
],
},
}) Defensive patterns
Strategy: validation
Validate before calling
// split workspace projects so the same file is not in both node and browser pools
export default defineConfig({
test: {
workspace: [
{ test: { name: 'unit', include: ['test/unit/**/*.test.ts'] } },
{ test: { name: 'browser', include: ['test/browser/**/*.test.ts'], browser: { provider: 'playwright' } } },
],
},
}) Type guard
// runtime guard inside shared code
function isBrowserPool(): boolean {
return globalThis.__vitest_worker__?.ctx?.pool === 'browser'
}
if (isBrowserPool()) {
// safe to use vitest/browser APIs here
} Prevention
- Use disjoint include globs between browser and node projects.
- Keep vitest/browser imports in test files, not in shared utils imported by node specs.
- Use a runtime pool check before dynamic-importing browser-only code.
When it happens
Trigger: A file imports `vitest/browser` (directly or transitively via a component library or shared util) and runs under `forks`, `threads`, `vmThreads`, or `typescript` pool. Typically because the file is matched by both a node test project and the browser project's include globs.
Common situations: Shared util/component imported by both node and browser specs; include globs too broad; a dependency unconditionally imports `vitest/browser`; typecheck pool trying to evaluate the module.
Related errors
- vitest/browser can be imported only inside the Browser…
- vitest/browser can be imported only inside the Browser…
- Vitest received --browser flag, but no project had a…
- Vitest wasn't able to resolve any project.
- All browser instances within a project must use the same…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/64b57332cbb967fc.
Report an issue: GitHub.
Appendix: source
Thrown at packages/browser/context.js:14
// Vitest resolves "vitest/browser" as a virtual module instead
// fake exports for static analysis
export const page = null
export const server = null
export const userEvent = null
export const cdp = null
export const commands = null
export const locators = null
export const utils = null
const pool = globalThis.__vitest_worker__?.ctx?.pool
throw new Error(
// eslint-disable-next-line prefer-template
'vitest/browser can be imported only inside the Browser Mode. '
+ (pool
? `Your test is running in ${pool} pool. Make sure your regular tests are excluded from the "test.include" glob pattern.`
: 'Instead, it was imported outside of Vitest.'),
)
View on GitHub (pinned to 1fa9837ec2)