Skip to main content
Beta: Front-End Checklist is currently in beta. Some issues are still being fixed. Thanks for your patience.

Use ES modules (import/export)

Use native ES module syntax for imports and exports instead of CommonJS require() to enable static analysis, tree-shaking, and better tooling support.

Utilities
Quick take
Typical fix time 15 min
  • Use import/export syntax instead of require()/module.exports
  • Named exports improve IDE autocompletion and enable tree-shaking
  • Add type="module" to script tags or use a bundler to load ES modules in browsers
  • Default exports are fine but named exports scale better in large codebases
Why it matters: ES modules are statically analyzable — bundlers can determine at build time what code is actually used and eliminate the rest (tree-shaking). CommonJS require() is dynamic and prevents this optimization. ES modules are also the browser-native standard, reducing the need for build-time transformation.

Rule Details

ES modules (import/export) are the JavaScript standard for code organization and are supported natively in all modern browsers and Node.js.

Code Example

// ❌ CommonJS (avoid for new code)
const utils = require('./utils')
const { formatDate } = require('./utils')
module.exports = { myFunction }
module.exports = myFunction
 
// ✅ ES Modules
import utils from './utils.js'
import { formatDate } from './utils.js'
export { myFunction }
export default myFunction

Why It Matters

ES modules are statically analyzable — bundlers can determine at build time what code is actually used and eliminate the rest (tree-shaking). CommonJS require() is dynamic and prevents this optimization. ES modules are also the browser-native standard, reducing the need for build-time transformation.

Named vs Default Exports

// utils.js — named exports (preferred for libraries and utilities)
export function formatDate(date) { /* ... */ }
export function formatCurrency(amount, currency) { /* ... */ }
export const MAX_ITEMS = 100
 
// consumer.js
import { formatDate, formatCurrency } from './utils.js'
// Only imported functions are included in the bundle
// UserCard.js — default export (common for single-concept modules)
export default function UserCard({ user }) { /* ... */ }
 
// consumer.js
import UserCard from './UserCard.js'
import MyCard from './UserCard.js' // Can rename default imports

In the Browser

<!-- Add type="module" to use import/export directly -->
<script type="module">
  import { formatDate } from './utils.js'
  console.log(formatDate(new Date()))
</script>

Module scripts are deferred by default, execute in strict mode, and have their own scope (no global leakage).

Dynamic Imports for Code Splitting

// Load a heavy module only when needed
async function loadChart() {
  const { Chart } = await import('./chart.js')
  return new Chart(document.getElementById('canvas'))
}
 
button.addEventListener('click', loadChart)

Re-exporting (Barrel Files)

// index.js — re-export from a central entry point
export { formatDate, formatCurrency } from './date-utils.js'
export { validateEmail, validatePhone } from './validators.js'
export { default as UserCard } from './UserCard.js'

Standards

  • Use MDN: JavaScript Guide as the standard for how this JavaScript pattern should behave in production, not just in a small local example.
  • Use web.dev: Learn JavaScript as the standard for how this JavaScript pattern should behave in production, not just in a small local example.

Support Notes

  • Module loading behavior depends on the target browser matrix and build pipeline, so verify the final shipped output rather than relying only on source syntax.
  • If legacy targets remain in scope, document the fallback or transpilation path explicitly.
  • ES modules and class bodies run in strict mode automatically. If the codebase still ships classic non-module scripts, an explicit 'use strict' directive can still matter there.

Verification

Automated Checks

  • Verify the behavior in the browser after the code change, not only in static analysis.
  • Inspect DevTools Network or Performance panels when the rule affects loading or execution order.
  • Test the primary user flow and one edge case triggered by the changed script path.

Manual Checks

  • Confirm the code still behaves correctly when the feature is delayed, lazy-loaded, or fails.

Use with AI

Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.

Check

Verify implementation

Identify any use of require(), module.exports, or exports in this JavaScript file that should be converted to ES module syntax.

Fix

Auto-fix issues

Convert all require() and module.exports statements to ES module import/export syntax.

Explain

Learn more

Explain the benefits of ES modules over CommonJS, including tree-shaking, static analysis, and browser support.

Review

Code review

Review scripts, client components, and browser execution paths related to Use ES modules (import/export). Flag exact imports, event handlers, runtime side effects, or blocking operations that violate the rule, and state how the change should be verified in the browser.

Sources

References used to support the guidance in this rule.

Further Reading

Tools and supplementary material for exploring the topic in more depth.

Rules that often go hand-in-hand with this one.

Split large JavaScript bundles

Use dynamic imports and route-based code splitting to break large bundles into smaller chunks that load on demand, reducing initial page load time.

JavaScript
Minify all JavaScript files

All JavaScript files are minified to reduce file size and improve loading performance.

JavaScript
Use import type for type-only imports

Use the import type syntax for imports that are only needed as TypeScript types, ensuring they are fully erased at compile time with zero runtime cost.

JavaScript
Enable TypeScript strict mode in tsconfig.json

Enable "strict": true in tsconfig.json to activate the full suite of TypeScript type-checking flags and catch the most common runtime bugs at compile time.

JavaScript

Was this rule helpful?

Your feedback helps improve rule quality. This stays internal for now.

Loading feedback...
0 / 385