Skip to content

JavaScript Tutorial Modules

Practical Project Structure with Modules

Lesson 173 of 258 2 min read By Deepak Paswan Updated Oct 4, 2026

Here is a clean way to organise a small front-end project with modules.

code
TEXT
my-app/
├── index.html
├── css/
│   └── styles.css
└── js/
    ├── main.js            ← entry point, wires things together
    ├── api.js             ← talks to the server (fetch helpers)
    ├── storage.js         ← localStorage helpers
    ├── utils/
    │   ├── format.js      ← formatPrice, formatDate...
    │   └── dom.js         ← small DOM helpers
    └── features/
        ├── todo.js        ← one feature = one file (or folder)
        └── cart.js
index.html
HTML
<script type="module" src="./js/main.js"></script>

main.js: the glue

js/main.js
JS
import { loadTodos } from "./features/todo.js";
import { initCart } from "./features/cart.js";

document.addEventListener("DOMContentLoaded", () => {
  loadTodos();
  initCart();
});

(With a module script you often do not need DOMContentLoaded, because modules are deferred.)

A feature module

js/features/todo.js
JS
import { loadJSON, saveJSON } from "../storage.js";
import { el } from "../utils/dom.js";

let todos = loadJSON("todos", []);

export function loadTodos() {
  render();
}

function render() {
  const list = document.querySelector("#todos");
  list.replaceChildren(...todos.map(t => el("li", t.text)));
}

export function addTodo(text) {
  todos = [...todos, { id: Date.now(), text }];
  saveJSON("todos", todos);
  render();
}

Guidelines

  1. One responsibility per module. If a file does three unrelated things, split it.
  2. Export only what others need. Keep helpers private.
  3. Dependencies flow one way. Features can use utilities, but utilities should not import features.
  4. Name files after what they contain, in a consistent style (kebab-case.js is common).
  5. Keep the entry file small. It starts things, it does not contain logic.
  6. Avoid circular imports.

Bundlers and npm

Real projects usually use npm to install libraries and a bundler (Vite, webpack, esbuild) to prepare code for the browser: it combines modules, removes unused code, and minifies. Imports like import dayjs from "dayjs" then work because the tool resolves the package. You can learn this later; modules in the browser work without it.

Legacy patterns you may meet

  • CommonJS: const x = require("./x"); module.exports = .... It is the older Node.js module system. Modern Node.js and bundlers support ES modules too.
  • IIFEs and global namespaces: (function () { ... })(); and window.MyApp = {}. They were the way to avoid globals before modules.
  • AMD / UMD: older browser module formats, still inside some libraries.

When you read such code, you can understand the idea: each tries to keep variables private and share a few things. For new code, use ES modules.

Growth plan

Start with a few files. Introduce folders when a folder would hold three or more related files. Do not create structure you do not need yet.

info
This course's projects
The later project lessons are written as single files so they run in the editor. In a real project, you would split them into modules following this structure.