Cómo solucionar 'Cannot use import statement outside a module'
Escribes una declaración import limpia, ejecutas tu código e inmediatamente te encuentras con esto:
SyntaxError: Cannot use import statement outside a module
Este error de módulos ES de JavaScript es una de las fuentes más comunes de confusión para desarrolladores que trabajan con Node.js, navegadores y entornos de pruebas. La solución no siempre es la misma, y aplicar la incorrecta empeora las cosas. A continuación te mostramos cómo diagnosticar tu situación y resolverla correctamente.
Puntos clave
- Este error es un desajuste del sistema de módulos, no un error de sintaxis — tu entorno de ejecución esperaba CommonJS pero encontró sintaxis
importde módulos ES. - En Node.js, establece
"type": "module"enpackage.jsono usa la extensión de archivo.mjspara optar por ESM. - En navegadores, añade
type="module"a tu etiqueta<script>para que el motor trate el archivo como un módulo ES. - En Jest, configura Babel para transformar ESM a CommonJS, y ajusta
transformIgnorePatternspara paquetes de terceros que solo usan ESM. - Siempre diagnostica primero tu entorno — Node.js, navegador o test runner — antes de aplicar una solución.
Por qué ocurre este error
El error significa que tu entorno de ejecución encontró sintaxis de módulos ES (import) pero esperaba algo diferente — generalmente CommonJS (require). Es un desajuste del sistema de módulos, no un error de sintaxis en tu código.
JavaScript tiene dos sistemas de módulos:
| Sistema | Sintaxis | Por defecto en |
|---|---|---|
| CommonJS (CJS) | require() | Node.js (legacy) |
| ES Modules (ESM) | import | Navegadores, Node.js moderno |
El entorno de ejecución decide qué sistema usar basándose en la configuración, no en el código en sí. Por eso la misma declaración import funciona en un proyecto y falla en otro.
Cómo solucionar el error Import Statement Outside Module en Node.js
Node.js trata los archivos .js como CommonJS a menos que se establezca "type": "module" en package.json. Para usar import, necesitas optar explícitamente por ESM.
Opción 1: Establecer "type": "module" en package.json
{
"name": "my-app",
"version": "1.0.0",
"type": "module"
}
Esto le indica a Node.js que trate todos los archivos .js del proyecto como módulos ES. Consulta la documentación oficial de módulos ES de Node.js para detalles sobre cómo Node determina el tipo de módulo.
Opción 2: Usar la extensión de archivo .mjs
Renombra tu archivo de app.js a app.mjs. Node.js siempre trata los archivos .mjs como ESM, independientemente de package.json.
Opción 3: Usar .cjs para archivos CommonJS
Si tu proyecto usa "type": "module" pero un archivo necesita require(), dale la extensión .cjs.
Importante: No simplemente añadas
"type": "module"sin verificar tus otros archivos. Cualquier archivo que userequire(),module.exportso__dirnamedejará de funcionar bajo ESM.
Solucionar el error en JavaScript del navegador
En navegadores, el import estático solo funciona dentro de un script de módulo. Si tu etiqueta <script> no declara type="module", el navegador lo trata como un script clásico y rechaza la sintaxis import.
<!-- Esto generará el error -->
<script src="app.js"></script>
<!-- Esto funciona -->
<script type="module" src="app.js"></script>
Este comportamiento es parte de la especificación estándar de módulos JavaScript implementada por los navegadores modernos.
Ten en cuenta que los scripts de módulo tienen ámbito limitado — las variables declaradas dentro de uno no están disponibles globalmente. Por eso podrías añadir type="module" y luego ver un ReferenceError para una variable que esperabas que fuera global. La solución es exportar e importar valores explícitamente en lugar de depender del ámbito global.
Discover how at OpenReplay.com.
Solucionar el error en Jest y otros entornos de pruebas
Jest se ejecuta en Node.js y tradicionalmente usa CommonJS por defecto, incluso si tu código fuente usa ESM. Esta es una fuente común del error “cannot use import statement outside a module” en suites de pruebas.
Un enfoque es configurar Babel para transformar ESM a CommonJS durante las pruebas:
// babel.config.js
module.exports = {
presets: ['@babel/preset-env'],
}
Alternativamente, Jest puede configurarse para ejecutar pruebas en modo ESM nativo si tu proyecto ya usa módulos ES. Consulta la documentación de módulos ECMAScript de Jest para más detalles.
Si un paquete de terceros (como swiper, lodash-es o bibliotecas similares que solo usan ESM) está causando el error, necesitas indicarle a Jest que lo transforme en lugar de ignorarlo:
// jest.config.js
module.exports = {
transformIgnorePatterns: [
'/node_modules/(?!(swiper|ssr-window|dom7)/)',
],
}
El punto clave: transformIgnorePatterns usa una búsqueda anticipada negativa. Estás diciendo “ignora todo en node_modules excepto estos paquetes”. Listarlos en entradas de array separadas no funcionará — deben combinarse en un único patrón regex con |.
Configuración de TypeScript
Si estás usando TypeScript, verifica tu tsconfig.json. El campo module controla qué sintaxis de módulo emite TypeScript en su salida compilada:
{
"compilerOptions": {
"module": "ESNext",
"target": "ESNext"
}
}
Establecer module en CommonJS mientras escribes declaraciones import es TypeScript válido — el compilador transformará import en require() en la salida. Sin embargo, establecer module en ESNext mientras ejecutas la salida en un entorno Node.js CommonJS (sin "type": "module" en package.json) generará el error en tiempo de ejecución. Asegúrate de que la configuración del módulo en tu tsconfig.json coincida con lo que tu entorno de ejecución realmente espera.
Diagnostica antes de solucionar
El mismo error aparece en diferentes entornos por diferentes razones. Antes de aplicar cualquier solución, pregúntate:
- ¿Dónde está ocurriendo el error — Node.js, navegador o test runner?
- ¿Qué dice el campo
"type"de tupackage.json? - ¿Estás usando un bundler o ejecutando archivos directamente?
Responder estas tres preguntas te señala la solución correcta cada vez.
Preguntas frecuentes
Sí, pero necesitas usar extensiones de archivo para distinguirlos. Los archivos con extensión .mjs siempre se tratan como módulos ES, y los archivos con extensión .cjs siempre se tratan como CommonJS, independientemente del campo type en package.json. Esto te permite usar ambos sistemas lado a lado en un único proyecto.
No. Cada paquete en node_modules tiene su propio package.json, por lo que tu campo type solo se aplica a los archivos de tu proyecto. Las dependencias definen su propio sistema de módulos de forma independiente. El error generalmente proviene de tus propios archivos o de importar una dependencia que solo usa ESM en un contexto CommonJS sin la transformación adecuada.
Los bundlers como Webpack y Vite procesan las declaraciones import durante el paso de compilación y producen un único archivo de salida. Resuelven la sintaxis de módulos antes de que el entorno de ejecución lo vea. Cuando ejecutas archivos directamente en Node.js o un navegador sin un bundler, el propio entorno de ejecución debe entender el formato del módulo, que es donde los desajustes causan este error.
Estas variables globales de CommonJS no están disponibles en módulos ES. En su lugar, puedes reconstruirlas usando import.meta.url. Por ejemplo, usa new URL(import.meta.url).pathname para obtener la ruta del archivo, o combínalo con el módulo path y fileURLToPath del módulo url para replicar el comportamiento de __dirname.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.