Skip to Content
JavaScript Intermediate: Write Code That Doesn't Fall Apart When the Data Changes
Intermediate
0 likes
Courses
JavaScript Intermediate: Write Code That Doesn't Fall Apart When the Data Changes

JavaScript Modules: import, export and Splitting One Big File

Split code into files with export and import, choose named or default exports, and run modules in Node and the browser. After this, you can break up a big file by job instead of by size.

Course content

Sign in to save your progress.

Course Home

Skip ahead: If you already split code into files with export and import and know why Node wants the .js extension, skip to "Common mistakes".

One 800-line app.js works. Until two people edit it on the same day, or you need the price calculation in a second page and copy it, and now there are two versions of it. Modules fix that. Each file holds one job, says what it shares with export, and other files take what they need with import. It's the normal way to organise JavaScript now, in the browser and in Node.

The smallest useful example

Three files in one folder. cart.js does the math:

export const VAT_RATE = 0.12;

export function subtotal(items) {
  return items.reduce((sum, item) => sum + item.price * item.qty, 0);
}

export function totalWithVat(items) {
  return subtotal(items) * (1 + VAT_RATE);
}

format.js formats money:

export default function peso(amount) {
  return `PHP ${amount.toFixed(2)}`;
}

main.js uses both:

import { subtotal, totalWithVat } from "./cart.js";
import peso from "./format.js";

const items = [
  { name: "Coffee", price: 180, qty: 2 },
  { name: "Bread", price: 65, qty: 1 },
];

console.log(peso(subtotal(items)));
console.log(peso(totalWithVat(items)));

Add a package.json with { "type": "module" } in the same folder, then run node main.js:

PHP 425.00
PHP 476.00

Anything a file doesn't export stays private to that file. That's a feature. Other files can't depend on a helper you meant to change later.

Named exports vs default export

  • Named (export function subtotal): imported with braces and the exact name, import { subtotal } from "./cart.js". A file can have many.
  • Default (export default function peso): imported without braces, under any name you like, import peso from "./format.js". A file has at most one.

My preference: use named exports almost everywhere. With named exports, a typo is an error the moment the file loads. With a default export, every file can call the same thing by a different name, and searching the project for it gets harder. Some frameworks expect a default export (for example, one component per file), so follow the framework when it asks.

You can also import everything a file exports as one object:

import * as cart from "./cart.js";
console.log(cart.VAT_RATE);

Running modules in Node

Node has two module systems. The older one, CommonJS, uses require() and module.exports. The newer one, ES modules, uses import and export. Node decides which one a .js file uses from the nearest package.json:

  • "type": "module": .js files are ES modules.
  • "type": "commonjs" (which npm init -y writes for you now): .js files are CommonJS, and import fails with "Cannot use import statement outside a module".
  • .mjs files are always ES modules and .cjs files are always CommonJS, whatever package.json says.

The tutorial Fix "Cannot use import statement outside a module" goes through every case.

⚠ Warning: In Node, write the file extension in relative imports: "./cart.js", not "./cart". Without it you get Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../cart' imported from .../main.js, followed by Did you mean to import "./cart.js"?. Bundlers like Vite let you leave it out, which is why code copied from a front-end project can fail in plain Node.

Running modules in the browser

Add type="module" to the script tag:

<script type="module" src="main.js"></script>

Module scripts are deferred automatically, so the page HTML is ready when they run. One catch: opening the HTML file by double-clicking it (a file:// address) blocks module imports in Chrome. Serve the folder with a local server instead, for example npx serve or your editor's Live Server.

How to split a big file

Don't split by size. Split by job. Ask "if this changes, what else changes with it?"

  • Price and tax math goes together (cart.js).
  • Formatting for display goes together (format.js).
  • Reading the page and wiring up buttons goes together (main.js).

main.js should read like a short summary: get the data, call the functions, show the result. If you open it and can't tell what the page does in 30 seconds, it's still doing too much.

Common mistakes

  • Missing .js in a Node import.
  • Asking for a name that isn't exported: SyntaxError: The requested module './cart.js' does not provide an export named 'total'. Check the spelling and that the other file actually exports it.
  • Using braces for a default export, or no braces for a named one.
  • Mixing require() and import in one file. In an ES module, require isn't defined.
  • Two files importing each other (a circular import). It sometimes works and sometimes gives undefined. Move the shared part into a third file.

What happens if you skip this

You'll keep one huge file, or worse, copy functions between files. Then a tax rule changes, you update one copy, and the other page keeps charging the old rate until a customer notices.

Open your biggest JavaScript file. If you had to move the money math into its own module today, which functions would go, and which would have to stay?

About

Split code into files with export and import, choose named or default exports, and run modules in Node and the browser. After this, you can break up a big file by job instead of by size.

Duration
5 min
Last update
08/26/2026
Was this helpful?
​ 0 ​ 0

Comments (0)

Sign in to comment

No comments yet.