Every Node.js project is built from modules: your own files, the modules built into Node, and packages from the npm registry. Knowing how modules load and how npm manages packages saves you from the most common "Cannot find module" and version-mismatch errors. This guide covers both module systems, the npm commands you use every day, and how to run a Node.js project on Domain India.
Node.js has two module systems: CommonJS (require and module.exports) and ES modules (import and export), which are the standard for new code. Set "type": "module" in package.json to use ES modules. Manage packages with npm, commit package-lock.json, and use npm ci for clean, repeatable installs. Use Node.js 22 or 24; Node.js 20 reached end of life in April 2026.
1. What a module is
A module is a file whose variables and functions stay private unless you export them. Node.js has three kinds:
- Your own modules: any
.js,.mjsor.cjsfile in your project, loaded with a relative path such as./math.js. - Core modules: built into Node, such as
fs,path,httpandcrypto. Load them with thenode:prefix, for examplenode:fs, so nobody can confuse them with an npm package of the same name. - Packages: code from the npm registry, installed into
node_modulesand loaded by name, such asexpress.
2. CommonJS: require and module.exports
CommonJS is Node's original module system, and a great deal of existing code still uses it.
// math.cjs
function add(a, b) {
return a + b;
}
module.exports = { add };// app.cjs
const { add } = require('./math.cjs');
const fs = require('node:fs');
console.log(add(5, 3)); // 8require loads a module synchronously the first time and caches it, so every later require of the same file returns the same object. Assign to module.exports (or add properties to exports), but never replace exports itself: exports = {...} silently exports nothing.
3. ES modules: import and export
ES modules (ESM) are the JavaScript standard, used in browsers and in modern Node.js. Turn them on for a whole project by adding "type": "module" to package.json, or name individual files .mjs.
// math.js
export const add = (a, b) => a + b;
export default function multiply(a, b) {
return a * b;
}// app.js
import multiply, { add } from './math.js';
import { readFile } from 'node:fs/promises';
const text = await readFile('notes.txt', 'utf8'); // top-level await works in ESM
console.log(add(5, 3), multiply(5, 3));Three rules catch most people out:
- Write the file extension in relative imports:
./math.js, not./math. __dirnameand__filenamedon't exist in ES modules. Useimport.meta.dirnameandimport.meta.filenamein current Node versions.- Load code lazily with
import(), which returns a promise, for exampleconst { default: sharp } = await import('sharp');. It works in both module systems.
| Question | CommonJS | ES modules |
|---|---|---|
| Syntax | require, module.exports | import, export |
| Enable with | Default, or .cjs files | "type": "module", or .mjs files |
| Loading | Synchronous | Asynchronous; top-level await allowed |
| Use for | Existing projects and older packages | All new code |
Mixing the two works in one direction easily: an ES module can import a CommonJS package. Recent Node versions can also require() an ES module, as long as it doesn't use top-level await.
4. npm and package.json
npm installs with Node.js. It downloads packages from the npm registry and records them in two files:
package.jsonlists your project's name, scripts and the version ranges of the packages it depends on. You edit it.package-lock.jsonrecords the exact version of every package installed, including packages your packages depend on. npm writes it. Commit it to Git, so every machine installs exactly the same versions.
Never commit node_modules; add it to .gitignore and reinstall from the lock file instead.
5. The npm commands you use every day
npm init -y # create package.json with defaults
npm install express # add a dependency
npm install -D eslint # add a devDependency (only needed while developing)
npm uninstall express # remove a package
npm outdated # list packages with newer versions
npm update # update within the ranges in package.json
npm ci # clean install exactly what package-lock.json says
npm ci --omit=dev # the same, without devDependencies (for production)
npm run build # run a script from package.json
npx create-vite@latest # run a package's command without installing it globallyUse npm install while you develop and change dependencies. Use npm ci on servers and in CI: it deletes node_modules, installs exactly what the lock file says, and fails if the lock file and package.json disagree.
Scripts live in package.json:
{
"type": "module",
"scripts": {
"start": "node server.js",
"dev": "node --watch server.js",
"test": "node --test"
}
}node --watch restarts on file changes and node --test runs Node's built-in test runner, so small projects no longer need extra tools for either.
6. Versions and semantic versioning
npm packages use semantic versioning, MAJOR.MINOR.PATCH: a major release may break your code, a minor one adds features, and a patch fixes bugs.
| Range in package.json | Accepts | Example for 5.1.0 |
|---|---|---|
| ^5.1.0 (npm's default) | Minor and patch updates | 5.1.1, 5.2.0, not 6.0.0 |
| ~5.1.0 | Patch updates only | 5.1.1, not 5.2.0 |
| 5.1.0 | Exactly this version | 5.1.0 only |
Dependencies are needed to run your app; devDependencies only to build or test it. peerDependencies are for plugins that expect the host package to be installed, and npm installs them automatically.
7. Keep your dependencies safe
Compromised and malicious packages on the npm registry are a real risk; several popular packages were hijacked in 2025.
- Run
npm auditregularly, andnpm audit fixfor safe fixes. Read whatnpm audit fix --forcewould change before you run it, because it can install breaking major versions. - Install from the lock file with
npm ci, so a new, unreviewed version never slips in during a deploy. - Add packages deliberately. Check the package's weekly downloads, maintainers and repository, and watch for look-alike names.
- Turn on two-factor authentication on your npm account if you publish packages.
- If
node_modulesseems corrupted, delete it and runnpm ci.npm cache verifychecks the cache; you rarely need to clear it.
8. Running a Node.js project on Domain India
Shared hosting (cPanel and DirectAdmin). The control panel's Node.js tool runs your app for you. On our cPanel servers it is Setup Node.js App, offering Node.js 20, 22 and 24; on DirectAdmin the Node.js selector offers versions 14 to 24 (measured 23 September 2026). Upload your code with package.json and package-lock.json but without node_modules, then click Run NPM Install and Start App. You don't need SSH for this. Build front-end or TypeScript projects on your own computer and upload the output, because large builds can run out of memory within your account's limits. The full steps are in Deploy a Node.js app on shared hosting.
Jailed SSH access is available on every shared hosting plan (cPanel, DirectAdmin, Webuzo). It is off by default; ask support to enable it for your account. You log in with an SSH key, and there is no root access, so install tools per project with npm and run them with npx rather than installing them globally. Tools available inside the jailed shell vary; ask support.
App Platform. For a production Node.js app, the App Platform detects your project from package.json, installs dependencies and runs your start script. Your app must listen on the PORT environment variable. Deploy from GitHub with Deploy Now, or with a deploy token from your CI. See Getting started with App Platform.
- 512 MB RAM per app
- 1 vCPU
- 5 GB NVMe SSD
- PostgreSQL Database
VPS. A VPS is self-managed with full root access, so you install the Node.js version you want and run your app with any process manager.
What is the difference between require and import in Node.js?
require belongs to CommonJS, Node's original module system, and loads modules synchronously. import belongs to ES modules, the JavaScript standard, which load asynchronously and allow top-level await. Use ES modules for new code by adding "type": "module" to package.json.
Why do I get "Cannot use import statement outside a module"?
Node is treating your file as CommonJS. Add "type": "module" to package.json, or rename the file to .mjs, or switch the file to require.
Should I commit package-lock.json?
Yes. It records the exact version of every installed package, so npm ci installs the same versions on every computer and server. Do not commit node_modules.
What is the difference between npm install and npm ci?
npm install adds or updates packages and can change package-lock.json. npm ci deletes node_modules and installs exactly what the lock file says, which makes it the right choice for servers and CI.
What does the caret (^) mean in package.json?
It allows minor and patch updates but not a new major version. For example, ^5.1.0 accepts 5.2.0 but not 6.0.0.
Can I run npm install on Domain India shared hosting?
Yes. On cPanel and DirectAdmin, the control panel's Node.js tool has a Run NPM Install button that installs your dependencies without SSH. Build large front-end projects on your own computer and upload the result.
Ready to run your Node.js app? Start on the App Platform, use cPanel hosting for a small app next to your website, or choose a VPS for full control.
Push your code from GitHub or your CI, and the App Platform installs your packages, runs your start script and serves your app over HTTPS.
See App Platform plans