Skip to content
Latchkey

Vite "Failed to resolve import" - Fix Import Resolution in CI

Vite could not find the module an import points at. As with Webpack's "Can't resolve", the cause is a missing package, a wrong or miscased path, or an alias Vite was never told about.

What this error means

The dev server or vite build errors with Failed to resolve import "<module>" from "<file>". Does the file exist? It is deterministic and points at the exact import.

vite output
[vite]: Internal server error: Failed to resolve import "./utils/forrmat" from "src/App.tsx".
Does the file exist?
  Plugin: vite:import-analysis
  File: /app/src/App.tsx

Diagnose it: is it resolution, transform, or memory?

Bundler failures in CI fall into three families and the error text often points at the wrong one. A module that resolves on your machine and not on the runner is nearly always case sensitivity or a missing optional dependency; a transform error is a config or version mismatch; and an unexplained kill with no stack is the out-of-memory reaper, not a build error at all.

Terminal
# 1. resolution: does the file exist with EXACTLY that case?
git ls-files | grep -i "the/imported/path"

# 2. transform: what versions is CI actually resolving?
npm ls webpack vite rollup esbuild typescript 2>/dev/null | head -20

# 3. memory: was it killed rather than failed?
#    exit 137 = SIGKILL (OOM). Nothing in the bundler log will explain it.
node --max-old-space-size=4096 node_modules/.bin/vite build

Common causes

Missing dependency or wrong path

The package is not installed, or the relative path is wrong (typo, wrong depth, missing extension where Vite expects one for non-JS).

Case-sensitivity on the runner

Linux CI is case-sensitive. ./Utils/format resolves on macOS but fails on the runner if the directory is actually utils.

Alias not configured

A @/ style alias used in source is not declared in resolve.alias (and mirrored from tsconfig paths), so Vite cannot map it.

How to fix it

Install the package and check the path/case

Terminal
npm install <package>
ls -la src/utils/format.ts   # exact case must match the import

Declare aliases in vite.config

Add resolve aliases (and keep them in sync with tsconfig paths).

vite.config.ts
// vite.config.ts
import { fileURLToPath, URL } from 'node:url'
export default defineConfig({
  resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } },
})

Make the build reproducible before you debug it

  • Pin the Node major in setup-node and in engines. A bundler that resolves native bindings will pick a different prebuilt binary across majors.
  • Delete node_modules locally and reinstall from the lockfile before concluding the runner is at fault; most "works locally" reports are stale local state.
  • Set CI=true locally to reproduce. Several toolchains change behaviour under it, including treating warnings as errors.
  • Exit code 137 is an out-of-memory kill. Raise --max-old-space-size or move to a larger runner rather than searching the bundler config.

How to prevent it

  • Commit a lockfile and install with npm ci for reproducible deps.
  • Match import casing to filenames; Linux runners are case-sensitive.
  • Generate Vite aliases from tsconfig paths to avoid drift.

Frequently asked questions

What causes Vite "Failed to resolve import"?
There are 3 common causes: missing dependency or wrong path, case-sensitivity on the runner, and alias not configured. The package is not installed, or the relative path is wrong (typo, wrong depth, missing extension where Vite expects one for non-JS).
How do I fix Vite "Failed to resolve import"?
There are 2 fixes depending on which cause you have: install the package and check the path/case and declare aliases in vite.config. Work through them in order, since the first is the most common.
What does Vite "Failed to resolve import" actually mean?
The dev server or vite build errors with Failed to resolve import "<module>" from "<file>".
How do I stop Vite "Failed to resolve import" happening again?
Commit a lockfile and install with npm ci for reproducible deps. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card