npm: The World's Biggest Toolbox

Junior Year, page 7 of 11. A four-minute read.

Here's one of the best things about JavaScript: you almost never have to build everything yourself. Developers all over the world share useful code as packages, and you can use them in your own projects for free.

These packages live in the npm registry, which holds well over two million packages. It's the largest collection of reusable code for any programming language. Need to format dates? There's a package. Make colorful terminal output? Package. Build a web server, resize images, validate email addresses, generate fake test data? Package, package, package, package.

npm (originally short for "Node Package Manager") is also the name of the tool you use to install them. It comes free with Node.js. Check it's there:

Terminal
npm --version

Starting a project: package.json

Every Node project has a package.json file in its main folder. It's like the project's ID card: its name, version, the packages it depends on, and handy shortcut commands. Create one by running this in a new, empty folder:

Terminal
npm init -y

(The -y means "yes to all the default answers.") You'll get a package.json that looks something like this:

package.json
{
  "name": "my-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Add "type": "module", to it so you can use import and export.

Installing a package

Let's install a popular little package called Day.js, which makes working with dates much easier than the built-in Date object from Grade 13:

Terminal
npm install dayjs

Three things happen:

  1. npm downloads the package into a folder called node_modules.
  2. It adds the package to a "dependencies" section in your package.json, like "dayjs": "^1.11.13" (your version number will probably be newer), so anyone else who gets your project knows it needs Day.js.
  3. It creates a file called package-lock.json, which records the exact version of every package installed, so everyone on your team gets identical versions.

Now you can import it, using just the package's name (no ./):

dates.js
import dayjs from "dayjs";

const today = dayjs("2026-10-15");
const christmas = dayjs("2026-12-25");

console.log(today.format("dddd, D MMMM YYYY"));
console.log(`Days until Christmas: ${christmas.diff(today, "day")}`);
console.log(`One month from now: ${today.add(1, "month").format("DD/MM/YYYY")}`);

Output

Thursday, 15 October 2026
Days until Christmas: 71
One month from now: 15/11/2026

So much nicer than counting milliseconds!

TipWhat does the ^ mean?

Package versions use three numbers, like 1.11.13, called semantic versioning: MAJOR.MINOR.PATCH. A patch update (1.11.14) fixes bugs. A minor update (1.12.0) adds features without breaking anything. A major update (2.0.0) might break things that used to work. The ^ in "^1.11.13" tells npm: "any newer version is fine, as long as the major number stays at 1." That way you get bug fixes automatically, but not surprise breaking changes.

node_modules and sharing your project

The node_modules folder can get huge (packages often depend on other packages, which depend on other packages...). You never edit it, and you never share it. When someone else downloads your project, they just run:

Terminal
npm install

and npm reads package.json and package-lock.json, and downloads everything they need. That's why, as you'll see shortly, developers tell Git to ignore the node_modules folder.

npm scripts

The "scripts" section of package.json lets you create shortcut commands for your project:

JSON
"scripts": {
  "start": "node index.js",
  "test": "node --test"
}

Now npm start runs your app, and npm test runs your tests. Every developer who opens your project knows exactly how to start it, without reading any instructions. (For script names other than start and test, use npm run name, like npm run build.)

Dev dependencies

Some packages are only needed while you're developing (like testing tools or code formatters), not when the app is actually running. Install those with --save-dev:

Terminal
npm install --save-dev prettier

They go into a separate "devDependencies" section.

Watch outBe careful what you install

Anyone can publish a package to npm, including the occasional bad actor. Before installing a package, check that it's popular and actively maintained (look at its page on npmjs.com: weekly downloads, last publish date, and the GitHub link). Double-check the spelling of the name, too. Scammers sometimes publish packages with names one letter off from popular ones, hoping you'll make a typo. And don't install a package for something you could write in three lines yourself!

Reading is step one

CurlyScript turns these notes into a game: short questions, an explanation after every answer, and a test at the end of each grade. Free, with nothing to sign up for.

Start learning