Fix Failed to resolve "@tailwindcss/vite": ESM only error
Why a Vite 6 project that builds fine refuses to load the Tailwind CSS v4 plugin, reproduced step by step, with the two one-line fixes and the variant newer plugin releases print.
TL;DR#
Vite reads vite.config.js as CommonJS when the nearest package.json has no "type": "module". It bundles the file, turns your import tailwindcss from "@tailwindcss/vite" into a require, and then checks that the package can be resolved that way. @tailwindcss/vite 4.1.13 and earlier only declare an import entry in their exports map, so Vite stops with Failed to resolve "@tailwindcss/vite". This package is ESM only. Rename the file to vite.config.mjs, or add "type": "module" to package.json. Either single change fixes it. The Vite 5 → 6 upgrade is not the cause: Vite 5 runs the same check.
The error, as npm run dev prints it (vite 6.2.0, @tailwindcss/vite 4.0.9):
✘ [ERROR] Failed to resolve "@tailwindcss/vite". This package is ESM only but it was tried to load by `require`. See https://vite.dev/guide/troubleshooting.html#this-package-is-esm-only for more details. [plugin externalize-deps]vite build reports the same failure, wrapped by esbuild:
node_modules/esbuild/lib/main.js:1217:27: ERROR: [plugin: externalize-deps] Failed to resolve "@tailwindcss/vite". This package is ESM only but it was tried to load by `require`. See https://vite.dev/guide/troubleshooting.html#this-package-is-esm-only for more details.The setup that triggers it#
The question comes from Stack Overflow: "Adding tailwindcss to an upgraded Vite v6 codebase causes ERROR Failed to resolve @tailwindcss/vite". A small React project, deployed to GitHub Pages, had just moved from Vite 5 to Vite 6 without trouble. The asker then followed the official Tailwind CSS guide for Vite: install tailwindcss and @tailwindcss/vite, add the plugin to the Vite config, put @import "tailwindcss"; in the stylesheet. Their vite.config.js was a textbook ES module:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [react(), tailwindcss()],
base: "/",
});What the question does not show is the line that is missing: their package.json has no "type" field. Projects scaffolded by npm create vite get "type": "module" (the React template of create-vite 6.2.0 has it on line 5). A project that started elsewhere, or was assembled by hand, often does not, and Vite then treats a .js config as CommonJS even when the file is written with import and export.
Why Vite refuses the plugin#
Vite does not hand vite.config.js straight to Node. It bundles the file with esbuild first, and the output format depends on one test. In vite 6.2.0, isFilePathESM returns true for .mjs and .mts, false for .cjs and .cts, and for anything else reads the nearest package.json and returns whether its type is module. bundleConfigFile then sets esbuild's format to esm or cjs accordingly.
Dependencies of the config are not bundled; they are left external and loaded at runtime. A plugin called externalize-deps decides that, and in the CommonJS case it resolves each bare import the way require would. When that fails but an import resolution succeeds, it throws the message from the error above. The check is in config.ts lines 1898–1916 at v6.2.0. The check is not new in Vite 6, which rules out the upgrade the question title blames: Vite 5's config loader throws the same error, pointing at the older vitejs.dev domain, and the same check and message are still in the config loader of the latest Vite release.
The other half is the plugin's own package.json. On the npm registry, @tailwindcss/vite 4.0.9 exports only this:
{ ".": { "types": "./dist/index.d.mts", "import": "./dist/index.mjs" } }There is no require or default condition, so a require resolution finds nothing, an import resolution finds index.mjs, and Vite concludes the package is ESM only. Because the check runs inside Vite before Node is asked to load anything, the Node version does not matter here: the reproduction below fails identically on the reporter's Node v23.4.0 and on Node v22.23.3, both of which can already load ES modules with require().
The Vite troubleshooting guide recommends converting the config to ESM rather than relying on newer runtimes, by adding "type": "module" to the nearest package.json or renaming vite.config.js/vite.config.ts to vite.config.mjs/vite.config.mts.
Fix#
Pick one of the two. Each was reproduced as the only change on top of the failing project.
-
Rename the config file to
.mjs. Nothing else in the project changes meaning. On a TypeScript config, the equivalent isvite.config.mts.bashmv vite.config.js vite.config.mjsThis is what the asker did in their own answer, the highest-voted one on the question.
-
Or mark the whole package as ES modules. Add one line to
package.json, next to"private":json{ "private": true, "type": "module", "scripts": { "dev": "vite", "build": "vite build" } }This is the second answer on the question, and it matches what new Vite projects ship with. The cost is that every
.jsfile in the package becomes an ES module, including apostcss.config.js, an oldtailwind.config.js, or a Node script that usesmodule.exportsandrequire. Rename those to.cjs, or rewrite them withexport default. A leftoverpostcss.config.jsthat starts withmodule.exports =, run by Node 22 inside a"type": "module"package, stops with:textReferenceError: module is not defined in ES module scopeIf that appears right after this change, it is the cause, and Node's own message names the fix (rename the file to
.cjs). The guide to exports is not defined in ES module scope walks through how Node picks the module system per file, and coversmodule.exportsas well asexports.
You do not need to touch DaisyUI, React or the Vite version. The Tailwind v4 Vite guide shows the plugin in a vite.config.ts and does not mention the module type; with plugin releases up to 4.1.13, that config only loads in a project that is already ESM.
Verify the fix#
The whole sequence was reproduced on 10 October 2026 in Docker, on Node v22.23.3 and again on the reporter's Node v23.4.0, with vite 6.2.0 and @tailwindcss/vite 4.0.9: a minimal project with @import "tailwindcss"; in src/style.css, a vite.config.js that only loads the Tailwind plugin, and a package.json without "type". vite build fails with the error above. Renaming the file to vite.config.mjs, and nothing else, gives:
dist/index.html 0.18 kB │ gzip: 0.16 kB
dist/assets/index-De2CT7Oq.css 39.06 kB │ gzip: 7.30 kB
✓ built in 735msGoing back to vite.config.js and adding "type": "module" instead builds the same files. In dev mode, the renamed config starts the server:
VITE v6.2.0 ready in 487 msTo confirm Tailwind is actually running, and not only that the config loads, search the built stylesheet for a class you used. grep -o 'text-3xl' dist/assets/*.css returned the class in both fixed variants. If the build now fails on "trying to use tailwindcss directly as a PostCSS plugin", a v3-era postcss.config.js still lists tailwindcss as a PostCSS plugin, which v4 no longer accepts; see Tailwind's PostCSS plugin has moved. For missing specifiers and npx tailwindcss init failures after a fresh install, see Cannot build frontend using Vite, TailwindCSS with PostCSS.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Newer @tailwindcss/vite: no error, or ERR_REQUIRE_ESM instead#
Tailwind changed the plugin's exports map in 4.1.14, released on 1 October 2025: the changelog lists "Use default export condition for @tailwindcss/vite" (PR 18948), which replaces import with default. Reading the map from the npm registry for each release confirms it: 4.0.9 and 4.1.13 declare "import": "./dist/index.mjs", 4.1.14 and 4.3.3 declare "default": "./dist/index.mjs". Since then a require resolution finds dist/index.mjs, Vite's check passes, and the outcome depends on whether your Node version can require() an ES module. The Node.js modules documentation records that this stopped needing a flag in the 22.12.0 release of the 22 line.
The same CommonJS project was rerun with @tailwindcss/vite 4.3.3, still on vite 6.2.0, on four Node versions. On Node v22.12.0 and v22.23.3 it builds without any change to the config (22.12.0 prints an ExperimentalWarning about loading an ES module with require()). On Node v22.11.0 and v20.18.0 it fails one step later than the original error, in Node rather than in Vite:
failed to load config from /tmp/app/vite.config.js
error during build:
Error [ERR_REQUIRE_ESM]: require() of ES Module /tmp/app/node_modules/@tailwindcss/vite/dist/index.mjs not supported.The fix is the same: vite.config.mjs or "type": "module" both built on Node 22.11.0 and 20.18.0 too. So if you see this variant, upgrading the plugin is not the answer, and upgrading Node only hides a CommonJS config that the next ESM-only plugin will trip over again. A related failure, where a package's exports map has no entry at all for the path or condition being asked for, is covered in ERR_PACKAGE_PATH_NOT_EXPORTED.
Check your own ESM error#
If your message is the Node form (ERR_REQUIRE_ESM, or "Cannot use import statement outside a module") rather than Vite's, paste it below to see which file Node treated as CommonJS and what to change. It runs in your browser; nothing is sent.
Runs entirely in your browser — nothing you paste is sent anywhere. Tokens and passwords that appear in paths or URLs are masked in the output.
Optional: package.json, file extension, Node.js version (sharper advice)
After the config loads#
Once Vite accepts the plugin, the next stumbling blocks in a Tailwind v4 migration are in the CSS, not the config. Projects that also install shadcn/ui commonly hit Cannot apply unknown utility class border-border, because Tailwind v4 no longer reads tailwind.config.js unless the stylesheet points at it, and shadcn init itself can stop with No Tailwind CSS configuration found when the CSS entry lacks @import "tailwindcss";.
The lasting point of this error is that vite.config.js is not automatically an ES module just because it is written with import. Vite asks package.json and the file extension, and so does Node. As more build plugins publish ESM only, a project without "type": "module" will keep meeting this message, so making the config explicitly .mjs, or the package explicitly ESM, is the change that stops it coming back.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix "Missing specifier" & npx tailwindcss init Errors
Why a clean npm install turns a working Vite + Tailwind build into three errors at once, reproduced one at a time with the fix for each.
Fix Rollup failed to resolve import "/src/main.tsx" in Vite
Vite build fails with 'Rollup failed to resolve '/src/main.tsx'' when index.html is placed inside src and the script tag uses an absolute path. Fix it by correcting the file structure.
Fix shadcn "No Tailwind CSS configuration found" in Vite
What shadcn init actually looks for before it says Tailwind is missing, reproduced on Tailwind 3 and 4 with the one line that fixes each.


