Vitest/Jest "import.meta" Undefined - env & glob Not Available in Tests
import.meta is an ESM-only construct. Under Jest’s default CommonJS runtime it is a syntax error, and even under Vitest, import.meta.env values depend on the resolved mode - so tests can see undefined where the app sees a value.
What this error means
A module using import.meta.env.VITE_X or import.meta.glob fails in tests: Jest throws "Cannot use import.meta outside a module," or Vitest reads import.meta.env.VITE_X as undefined even though the dev build has it.
SyntaxError: Cannot use 'import.meta' outside a module
> 3 | const base = import.meta.env.VITE_API_URL;
| ^
(Jest, default CommonJS runtime)Diagnose it: flake, environment, or genuine failure?
Before debugging the assertion, establish whether the test is deterministic. A test that fails only in CI is usually order-dependent, time-dependent, or racing something, and fixing the assertion will not help.
# does it fail in isolation?
npx vitest run path/to/file.test.ts
# is it order dependent? run the suite in a random order twice
npx vitest run --sequence.shuffle
# is it a race? run the same file repeatedly
for i in $(seq 1 20); do npx vitest run path/to/file.test.ts || break; doneCommon causes
Jest CommonJS has no import.meta
Jest transpiles to CommonJS by default, where import.meta does not exist. Code that reads import.meta.env breaks at parse/eval time unless mapped or polyfilled.
Vitest env not loaded for tests
Vitest exposes import.meta.env, but only variables present in the resolved mode/.env are defined. A VITE_-prefixed var missing from the test environment reads as undefined.
How to fix it
In Vitest, provide env values for tests
Define the values Vitest should expose, or set them in a setup file.
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
define: { 'import.meta.env.VITE_API_URL': JSON.stringify('http://localhost') },
test: { env: { VITE_API_URL: 'http://localhost' } },
});In Jest, avoid raw import.meta
- Read config through a small wrapper (
getApiUrl()) you can mock in Jest, instead ofimport.metainline. - Or run Jest in native ESM (
NODE_OPTIONS=--experimental-vm-modules) with a transform that preservesimport.meta. - Provide a Babel plugin to rewrite
import.meta.envtoprocess.envfor the Jest build.
CI-only causes worth ruling out
- Runners have fewer cores than a laptop, so timing-sensitive tests that pass locally fail under contention.
- No TTY and a different locale or timezone. Snapshot tests containing formatted dates or numbers are the usual casualty; pin
TZandLANGin the job. - Parallel workers sharing a database, a port, or a temp directory. Give each worker its own namespace.
- Default timeouts calibrated on a fast machine. A cold runner is slower on first execution, especially before any cache warms.
How to prevent it
- Centralize env access behind a wrapper so tests can mock it.
- Define required
import.meta.envvalues in the Vitest config. - Prefer Vitest for Vite apps that lean on
import.meta.