Fix: Directory import is not supported resolving ES modules
Why Node throws ERR_UNSUPPORTED_DIR_IMPORT under "type": "module", three fixes reproduced on Node 24, and why the old specifier flag no longer helps.
TL;DR#
Under "type": "module" (or in a .mjs file), Node.js resolves relative and absolute import paths the way a browser does: it loads the exact file you name and never looks inside a folder for an index.js. import database from './database' therefore fails with ERR_UNSUPPORTED_DIR_IMPORT. Write the full path, ./database/index.js, or give the folder a short name in the package.json "imports" map (#database) and import that. The --experimental-specifier-resolution=node flag from older answers was removed in Node.js 19.0.0: on current releases it changes nothing.
The error#
The Stack Overflow question behind this page has an app.js that imports ./database, a database/index.js next to it, and "type": "module" in package.json. The same layout, rebuilt in a throwaway node:24-bookworm-slim container on 11 October 2026, fails with:
Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '/w/src/database' is not supported resolving ES modules imported from /w/src/app.js
code: 'ERR_UNSUPPORTED_DIR_IMPORT',
url: 'file:///w/src/database'
}
Node.js v24.21.0Node.js 18.20.8 and 22.23.3 print the same first line for the same files. The first path is the folder Node.js refused to load, and the second is the file that contains the faulty import. That second path is what tells you where to look, especially when it points inside node_modules (see the last section).
Why it happens#
Node.js has two module loaders with two resolution algorithms. CommonJS require('./database') tries ./database.js, then ./database/index.js, and so on. The ES module loader does none of that. The ESM documentation is explicit:
A file extension must be provided when using the
importkeyword to resolve relative or absolute specifiers. Directory indexes (e.g.'./startup/index.js') must also be fully specified.
The specifier ./database therefore resolves to the URL file:///w/src/database. Node.js finds a directory at that URL, not a file, and throws the error that the errors reference describes as "import a directory URL is unsupported". If nothing at all existed at that URL (a file imported without its .js extension, for instance), the same check in Node's resolver source would throw ERR_MODULE_NOT_FOUND instead. That extensionless-file case has its own page: ERR_MODULE_NOT_FOUND for a relative import without .js.
As a control, the same database/index.js folder loads through require('./database') in a CommonJS package on Node.js 24.21.0. The folder layout is not the problem. The folder lookup is something only require() does, so an index-file layout breaks as soon as the importing file is loaded as an ES module. Switching a package to "type": "module" has a second effect, also seen in the reproduction on Node.js 24.21.0: a .js file in that package that still calls require() stops with require is not defined in ES module scope. That is the per-file CommonJS-or-ESM decision covered in exports is not defined in ES module scope, where keeping such files as .cjs is one of the fixes.
Check your own error message#
Paste the full error, including the imported from line, into the explainer below. It picks out the folder Node.js refused and gives the matching fixes: name the index file, or import through the package name and an "exports" subpath. It runs in your browser and 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)
Fix#
1. Name the index file#
This is the fix from the accepted answer, and it changes one line:
// src/app.js
import database from './database/index.js';
await database();Run it again:
node src/app.jsdatabase: connect() calledApply the same rule to every relative import in the project. Folders need /index.js, and files need their extension (./config.js, not ./config). This output assumes database/index.js declares its function properly. With the file exactly as posted in the question, the next run fails with a ReferenceError instead, which is fixed further down.
2. Or give the folder a short name in "imports"#
If you prefer a short specifier, declare it once in package.json. The packages documentation says entries in this field must start with #, and they only apply to imports made from inside the package itself:
{
"name": "node-starter",
"version": "1.0.0",
"type": "module",
"imports": {
"#database": "./src/database/index.js"
}
}// src/app.js
import database from '#database';
await database();Node.js 24.21.0 loads it and prints database: connect() called. The map points at a file, so there is still no directory lookup. It is just written once instead of in every import.
3. Or self-reference the package through "exports"#
The errors reference recommends a third route: list a subpath in "exports" and import the package by its own name. With "exports": { ".": "./src/app.js", "./database": "./src/database/index.js" } in the same package.json, import database from 'node-starter/database' also loads on Node.js 24.21.0. Use this when the folder is part of what the package offers to other code. For something internal, "imports" keeps it private.
Verify the fix#
Run the entry file directly, with no flag:
node src/app.jsIf it now fails with a different error, read the second path in the message again. It may point at a deeper file that has the same kind of import. Fix them one at a time until the program starts.
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.
The question's own code fails next#
Once the path is fixed, the database/index.js from the question fails on its first line:
export default connect = async () => {
^
ReferenceError: connect is not definedexport default connect = … assigns to a variable that was never declared, and modules always run in strict mode, where that assignment throws a ReferenceError. Declare the function instead:
// src/database/index.js
export default async function connect() {
try {
console.log('database: connect() called');
} catch (error) {}
}With that change, the reproduction prints database: connect() called. In real code, replace the empty catch with error handling. A swallowed connection error only resurfaces later as a confusing failure.
The flag from older answers no longer exists#
The second-highest answer recommends node --experimental-specifier-resolution=node app.js. On Node.js 18.20.8 this still works. It prints ExperimentalWarning: The Node.js specifier resolution flag is experimental and loads the folder. The flag was removed in Node.js 19.0.0 (changelog, PR #44859). What makes it a trap is how current releases react. On Node.js 22.23.3 and 24.21.0 the command still starts without any warning about the flag, then fails with the exact same ERR_UNSUPPORTED_DIR_IMPORT. If a script or a Dockerfile still carries the flag, it does nothing. Remove it and fix the imports.
TypeScript compiles the bad import under one setting only#
In a TypeScript project, the compiler setting decides whether you see the problem at build time or at run time. With "module": "nodenext", TypeScript 6.0.3 rejects the folder import before anything runs:
src/app.ts(1,22): error TS2834: Relative import paths need explicit file extensions in ECMAScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Consider adding an extension to the import path.The fix is the same one, written with the .js extension of the output file, even in a .ts source:
// src/app.ts
import database from './database/index.js';
await database();{
"compilerOptions": {
"module": "nodenext",
"target": "es2022",
"rootDir": "src",
"outDir": "dist",
"strict": true
},
"include": ["src"]
}The "rootDir" line matters on TypeScript 6: without it, tsc stops with TS5011 before checking the imports. With "module": "esnext" and "moduleResolution": "bundler", the same extensionless import compiled with no error on TypeScript 6.0.3. Running the emitted dist/app.js with plain Node.js then throws Directory import '/t/dist/database' is not supported. If the output runs on Node.js without a bundler, nodenext is the setting that catches every folder import at compile time. If the project runs through ts-node and the error is about require() rather than a folder, that is a different problem: see ERR_REQUIRE_ESM in ts-node.
When the path points inside node_modules#
If the folder in the message sits in node_modules, the faulty import is in a published package, not in your code. In next-auth issue #9202, a release of @auth/core imported lib/actions from lib/index.js as a folder. Projects that built it with Vite then failed with this exact message. The maintainer closed it as fixed via PR #9205 and asked users to upgrade. Do the same: upgrade the package, or pin the release before the one that broke. Editing files in node_modules will not survive the next install.
The other case is your own deep import of a package folder. Mongoose 9.11.1 has no "exports" field, so its internal folders can be reached by path, and import driver from 'mongoose/lib/drivers/node-mongodb-native' fails on Node.js 24.21.0 with the same error plus a hint:
Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '/m/node_modules/mongoose/lib/drivers/node-mongodb-native' is not supported resolving ES modules imported from /m/src/dep.js
Did you mean to import "mongoose/lib/drivers/node-mongodb-native/index.js"?Importing the suggested …/node-mongodb-native/index.js path loads the module. The hint did not appear for the relative ./database import on the same Node.js release, so do not count on it. When a package does publish an "exports" map and that map leaves the folder out, the error you get is a different one, ERR_PACKAGE_PATH_NOT_EXPORTED. Import an entry the map lists, as explained in ERR_PACKAGE_PATH_NOT_EXPORTED: subpath not in exports.
Folder imports are not the only import rule that differs from require(). A JSON file loaded with import needs an import attribute, covered in ERR_IMPORT_ASSERTION_TYPE_MISSING when importing JSON. For the folder import itself, the durable fix is the boring one: write the index file you mean, and let "imports" shorten it if the paths get long.
Further reading: Fix Day.js: dayjs_1.default is not a function. Also see Fix "X is not a constructor" from a plain require(). Also see Fix Babel "native ECMAScript module configuration file". Also see Import a directory of files in a loop: TS1343, require().
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 ERR_MODULE_NOT_FOUND: relative import missing .js
Why an Express app with "type": "module" cannot find ./config/app, why the flags from older answers now do nothing, and how TypeScript catches it at compile time.
Fix: exports is not defined in ES module scope
How Node decides CommonJS vs ES module, and three remedies for aligning source syntax, compiler output and the runtime.
Import a directory of files in a loop: TS1343, require()
Two working loaders for a folder of Express route files, one synchronous and one async, plus the startup-order bug that forEach with import() hides. Reproduced in Docker.


