vitest-dev/vitest · error · Error

vitest/browser can be imported only inside the Browser Mode.

Error message

vitest/browser can be imported only inside the Browser Mode. Instead, it was imported outside of Vitest.

What it means

Same virtual-module guard as the pool variant, but here `globalThis.__vitest_worker__` is undefined or has no ctx.pool — meaning the module is being imported outside any vitest worker at all (no test runner present). The fallback throws telling you the import happened outside vitest entirely.

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)

Solutions

  1. Run the file under vitest with the browser pool instead of node/tsx/vite directly.
  2. Mark `vitest/browser` as external in build/eslint configs that should not evaluate it.
  3. Move shared helpers out of files that import `vitest/browser` so non-vitest tooling does not pull it in.
  4. Use a dynamic import gated on a vitest-only environment check for code shared with non-vitest contexts.

Example fix

// before
// utils.shared.ts imported by both vitest browser tests and a node script
import { page } from 'vitest/browser' // throws when node script runs

// after
// keep the vitest/browser import inside test-only files; shared utils take page as a parameter
export function fillForm(p: Page) { /* ... */ }
// test file (vitest only):
import { page } from 'vitest/browser'
fillForm(page)
Defensive patterns

Strategy: type-guard

Validate before calling

// before importing vitest/browser in shared code, ensure a vitest worker exists
const inVitest = typeof globalThis.__vitest_worker__ !== 'undefined'
const inBrowserPool = globalThis.__vitest_worker__?.ctx?.pool === 'browser'

// only dynamic-import when both are true

Type guard

function isVitestBrowserWorker(): boolean {
  return globalThis.__vitest_worker__?.ctx?.pool === 'browser'
}

Prevention

When it happens

Trigger: Running the file with plain node/tsx/vite outside vitest; importing a browser test module from a script, a Storybook story, an ESLint rule, a build step, or a non-vitest test runner (jest).

Common situations: Tooling that statically evaluates or imports test files (eslint import/no-unresolved, storybook, typecheck scripts, unit tests in another framework); a dev script that loads test utilities; SSR/build accidentally bundling the browser module.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/d82dbb6e298aa262. Report an issue: GitHub.