Modules and Imports
Modules and Imports
When you look at AI-generated code, you'll see import and require statements at the top of every file. These are how Node.js files share code with each other. Understanding this system is key to reading and working with any project.
What is a Module?
A module is simply a file that exports some code (functions, variables, classes) so other files can use it. Every .js or .ts file in Node.js is a module.
Think of modules like LEGO bricks — each one does something specific, and you snap them together to build your application.
Two Module Systems
Node.js has two ways to handle imports. This confuses many beginners, so let's clear it up:
| Feature | CommonJS (CJS) | ES Modules (ESM) |
|---|---|---|
| Syntax | require() / module.exports | import / export |
| File extension | .js (default) | .mjs or .js with "type": "module" |
| Age | Original Node.js system | Newer, modern standard |
| Used in | Older projects, config files | Modern projects, TypeScript |
| Loading | Synchronous | Asynchronous |
CommonJS (The Old Way)
// ── math.js ─── Exporting function add(a, b) { return a + b; } function multiply(a, b) { return a * b; } module.exports = { add, multiply }; // ── app.js ─── Importing const { add, multiply } = require("./math"); console.log(add(2, 3)); // 5 console.log(multiply(4, 5)); // 20
ES Modules (The Modern Way)
// ── math.js ─── Exporting export function add(a, b) { return a + b; } export function multiply(a, b) { return a * b; } // ── app.js ─── Importing import { add, multiply } from "./math.js"; console.log(add(2, 3)); // 5 console.log(multiply(4, 5)); // 20
Which Should You Use?
Use ES Modules (import/export) for new projects. It's the modern standard, and all TypeScript projects use this syntax. When you see require() in older code, just know it does the same thing as import.
To enable ES Modules in a Node.js project, add this to your package.json:
{ "type": "module" }
What to ask your AI: "Should this project use CommonJS or ES Modules? Convert the require statements to import syntax."
Named vs Default Exports
There are two styles of exporting from a module:
Named Exports
You can export multiple things from one file. When importing, you use curly braces {}:
// ── utils.ts ─── Multiple named exports export function formatDate(date: Date): string { return date.toLocaleDateString(); } export function formatCurrency(amount: number): string { return `$${amount.toFixed(2)}`; } export const MAX_RETRIES = 3; // ── app.ts ─── Import specific items by name import { formatDate, formatCurrency, MAX_RETRIES } from "./utils";
Default Exports
Each file can have one default export. When importing, you don't use curly braces and can name it anything:
// ── Database.ts ─── Default export class Database { async connect() { /* ... */ } async query(sql: string) { /* ... */ } } export default Database; // ── app.ts ─── Import the default (name it whatever you want) import Database from "./Database"; import DB from "./Database"; // Same thing, different name
Combining Both
A file can have both named exports and a default export:
// ── api.ts export const BASE_URL = "https://api.example.com"; export function buildUrl(path: string) { return BASE_URL + path; } // Default export const apiClient = { get, post, put, delete: del }; export default apiClient; // ── app.ts import apiClient, { BASE_URL, buildUrl } from "./api";
Importing from npm Packages vs Local Files
This is an important distinction:
// ── npm packages — just the package name, no path import express from "express"; import { OpenAI } from "openai"; import dotenv from "dotenv"; // ── Local files — start with ./ or ../ import { add } from "./math"; import Database from "../services/Database"; import { User } from "../../types/User";
The rule is simple:
- No dot prefix = npm package (installed in node_modules)
- Starts with ./ or ../ = a file in your project
Path Resolution
When you import a local file, Node.js looks for the file following these rules:
// If you write: import { helper } from "./utils"; // Node.js looks for (in order): // 1. ./utils.ts // 2. ./utils.js // 3. ./utils/index.ts // 4. ./utils/index.js
The index file pattern is common for organizing code:
src/
services/
index.ts <-- Re-exports everything
userService.ts
postService.ts
authService.ts
// ── services/index.ts ─── Re-export from one place export { UserService } from "./userService"; export { PostService } from "./postService"; export { AuthService } from "./authService"; // ── app.ts ─── Clean import from the folder import { UserService, PostService, AuthService } from "./services";
Relative Paths Explained
./ = current directory
../ = parent directory (one level up)
Example project structure:
src/
routes/
users.ts <-- You're in this file
services/
userService.ts
utils/
helpers.ts
// From src/routes/users.ts: import { UserService } from "../services/userService"; // Go up one, into services import { helpers } from "../utils/helpers"; // Go up one, into utils
TypeScript and Import Resolution
TypeScript adds a few things to imports:
Type-Only Imports
// Import a type (removed at runtime — only used for type checking) import type { User } from "./types"; // Import both values and types import { createUser, type User, type CreateUserInput } from "./users";
Path Aliases (tsconfig)
In TypeScript projects, you'll often see clean paths instead of long relative paths:
// Without path aliases (messy) import { Button } from "../../../components/ui/Button"; // With path aliases (clean) import { Button } from "@/components/ui/Button";
This is configured in tsconfig.json:
{ "compilerOptions": { "paths": { "@/*": ["./src/*"] } } }
What to ask your AI: "Set up path aliases in my TypeScript project so I can use @/ instead of long relative imports."
Common Import Patterns in AI Projects
Here are real-world imports you'll see in AI-generated code:
// Web server import express from "express"; import cors from "cors"; // AI SDK import { OpenAI } from "openai"; import Anthropic from "@anthropic-ai/sdk"; // Firebase import { initializeApp } from "firebase/app"; import { getFirestore, collection, getDocs } from "firebase/firestore"; // Environment variables import dotenv from "dotenv"; dotenv.config(); // Node.js built-in modules import fs from "fs"; import path from "path";
What's Next?
You now understand how Node.js files connect through imports and exports. The next tutorial covers working with files and environment variables — two things you'll do constantly in AI-powered applications.
What to ask your AI: "I'm getting an import error. Here's the file structure and the import statement: [paste details]. What's wrong?"