npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

modfix

v1.0.1

Published

Automatically detect and configure the correct module system (ESM/CJS) to fix 'Cannot use import statement outside a module' and related errors

Downloads

21

Readme

modfix 🔧

Automatically detect and fix ESM/CommonJS module configuration issues

npm version License: MIT Node.js

modfix solves the #1 most upvoted npm-related question on StackOverflow: "Cannot use import statement outside a module" (701 votes, 1.9M views).

The Problem

SyntaxError: Cannot use import statement outside a module

This error occurs when Node.js tries to parse ES modules (import/export) in a CommonJS context. It affects:

  • TypeScript projects
  • Babel setups
  • Modern Node.js applications
  • Projects migrating from CJS to ESM

modfix automatically detects your project's module system and fixes the configuration.

Installation

# Global installation (recommended for CLI)
npm install -g modfix

# Local installation
npm install modfix

# Run without installing
npx modfix analyze

Quick Start

# Analyze your project for issues
modfix analyze

# Auto-fix configuration (package.json, tsconfig.json)
modfix fix

# Convert code from CommonJS to ESM
modfix migrate --target esm

# Interactive setup
modfix init

CLI Commands

modfix analyze [path]

Scan a project and report module configuration issues.

modfix analyze                    # Analyze current directory
modfix analyze ./my-project       # Analyze specific path
modfix analyze --verbose          # Show detailed file info
modfix analyze --json             # Output as JSON

Example output:

🔍 Analyzing project...

Project Analysis Report
──────────────────────────────────────────────────

Project: /path/to/my-project
Package.json: /path/to/my-project/package.json
Configured type: None
Recommended type: esm

Files analyzed:
  Total: 15
  ESM syntax: 12
  CJS syntax: 3

Issues found:
  2 error(s)
  1 warning(s)

Errors:
✖ ESM syntax (import/export) used in CommonJS context
   /path/to/my-project/src/index.js
   → Add "type": "module" to package.json or rename file to .mjs

Recommendation:
  Run modfix fix --target esm to configure your project for ESM

modfix fix [path]

Auto-fix module configuration in package.json and tsconfig.json.

modfix fix                        # Fix with auto-detected target
modfix fix --target esm           # Configure for ES Modules
modfix fix --target cjs           # Configure for CommonJS
modfix fix --dry-run              # Preview changes without writing
modfix fix --exports              # Add "exports" field for dual package
modfix fix --interactive          # Interactive mode with prompts

What it does:

  • Sets "type": "module" or "type": "commonjs" in package.json
  • Updates tsconfig.json with correct module/moduleResolution settings
  • Optionally adds "exports" field for dual ESM/CJS package support
  • Adds "engines": {"node": ">=18.0.0"}

modfix migrate [path]

Convert source code between ESM and CommonJS syntax.

modfix migrate                    # Convert to ESM (default)
modfix migrate --target cjs       # Convert to CommonJS
modfix migrate --dry-run          # Preview transformations
modfix migrate --verbose          # Show detailed changes
modfix migrate -f src/index.js    # Migrate specific files

Transformations:

ESM → CJS:

// Before (ESM)
import fs from 'fs';
import { join } from 'path';
export default function hello() {}
export const name = 'world';

// After (CJS)
const fs = require('fs');
const { join } = require('path');
function hello() {}
const name = 'world';
module.exports = hello;
module.exports.name = name;

CJS → ESM:

// Before (CJS)
const fs = require('fs');
const { join } = require('path');
module.exports = { hello, name };

// After (ESM)
import fs from 'fs';
import { join } from 'path';
export { hello, name };

modfix init

Interactive setup wizard (alias for modfix fix --interactive).

modfix init

Programmatic API

Use modfix in your Node.js scripts:

import { analyze, fix, migrate, detect } from 'modfix';

// Analyze a project
const report = await analyze('./my-project');
console.log(report.issues);        // Array of issues
console.log(report.recommendedType); // 'esm' | 'cjs' | 'mixed'

// Fix configuration
const results = await fix('./my-project', {
  target: 'esm',      // 'esm' | 'cjs'
  dryRun: false,      // Preview without changes
  addExports: true    // Add exports field
});

// Migrate code
const migration = await migrate('./my-project', {
  target: 'esm',
  dryRun: false,
  files: ['src/index.js']  // Optional: specific files
});

// Detect single file
const fileInfo = await detect('./src/index.js');
console.log(fileInfo.effectiveType);  // 'module' | 'commonjs'
console.log(fileInfo.usesESMSyntax);  // boolean
console.log(fileInfo.usesCJSSyntax);  // boolean

Advanced API

import {
  // Analysis
  analyzeProject,
  analyzeFile,
  generateSummary,
  
  // Detection
  detectSyntaxWithLexer,
  getPackageType,
  getModuleTypeFromExtension,
  
  // Fixing
  fixPackageJson,
  fixTsConfig,
  generateExportsField,
  
  // Transformation
  cjsToEsm,
  esmToCjs,
  transformFile,
  previewTransform,
  
  // Utilities
  findNearestPackageJson,
  getFilesRecursive
} from 'modfix';

// Transform code directly
const result = cjsToEsm(`
const fs = require('fs');
module.exports = { readFile: fs.readFile };
`);

console.log(result.code);
// import fs from 'fs';
// export { readFile: fs.readFile };

How It Works

Detection Algorithm

  1. File Extension: .mjs/.mts → ESM, .cjs/.cts → CJS
  2. package.json: Walks up directory tree to find nearest package.json and reads "type" field
  3. Syntax Analysis: Uses es-module-lexer for fast parsing:
    • import/export statements → ESM
    • require()/module.exports → CJS
    • import.meta → ESM
    • __dirname/__filename → CJS

Issue Detection

| Issue Code | Description | |------------|-------------| | ESM_IN_CJS | ESM syntax used in CommonJS context | | CJS_IN_ESM | CommonJS syntax used in ESM context | | MIXED_SYNTAX | File contains both ESM and CJS syntax | | NO_PACKAGE_JSON | No package.json found | | NO_TYPE_FIELD | Missing "type" field in package.json | | TS_MODULE_MISMATCH | tsconfig.json module setting conflicts with package.json |

Configuration Generated

package.json (ESM)

{
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    }
  },
  "engines": {
    "node": ">=18.0.0"
  }
}

tsconfig.json (ESM)

{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "target": "ES2022",
    "esModuleInterop": true,
    "strict": true,
    "outDir": "./dist",
    "declaration": true
  }
}

Common Use Cases

Fixing "Cannot use import statement outside a module"

# Quick fix
modfix fix --target esm

Migrating a CJS Project to ESM

# 1. Analyze current state
modfix analyze

# 2. Convert code
modfix migrate --target esm

# 3. Update configuration
modfix fix --target esm --exports

Setting Up a Dual ESM/CJS Package

modfix fix --target esm --exports

Then build both versions with your bundler (esbuild, rollup, etc.).

Checking a Project in CI

modfix analyze --json | jq '.issues | length'
# Returns number of issues, exit code 0 if no errors

Requirements

  • Node.js: >= 18.0.0
  • Supported files: .js, .ts, .jsx, .tsx, .mjs, .cjs, .mts, .cts

Limitations

  • Dynamic imports: Can't statically analyze dynamic require() or import() with variables
  • Monorepos: Currently analyzes single packages; workspace support planned for v2
  • Bundler configs: Doesn't generate webpack/rollup/esbuild configs (use their respective init tools)

Roadmap

v1.x (Current)

  • ✅ Project analysis and issue detection
  • ✅ Auto-fix package.json and tsconfig.json
  • ✅ Code transformation (CJS ↔ ESM)
  • ✅ CLI with analyze, fix, migrate commands
  • ✅ Programmatic API

v2.0 (Planned)

  • ⬜ Monorepo/workspace support
  • ⬜ Watch mode for continuous fixing
  • ⬜ Babel config generation
  • ⬜ VS Code extension
  • ⬜ Git integration (auto-commit fixes)

v3.0 (Future)

  • ⬜ AI-powered migration suggestions
  • ⬜ Custom rule definitions
  • ⬜ Plugin system

Contributing

Contributions are welcome! Please read our Contributing Guide first.

# Clone the repo
git clone https://github.com/yourusername/modfix.git
cd modfix

# Install dependencies
npm install

# Run tests
npm test

# Run CLI locally
node bin/modfix.js analyze ./test-project

License

MIT © Harshit