javascript-today

NPM Basics

NPM (Node Package Manager) is the world’s largest software registry with over 2 million packages. It comes bundled with NodeJS and is essential for modern JavaScript development.

What is NPM?

NPM serves two main purposes:

  1. Package manager: Install and manage third-party libraries
  2. Script runner: Run build scripts, tests, and development servers

Every NodeJS project uses a package.json file to manage dependencies and scripts.

Creating a New Project

Initialize a new Node project:

# Interactive setup
npm init

# Skip questions (use defaults)
npm init -y

This creates 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"
}

Installing Packages

Install a Package

# Install and add to dependencies
npm install express

# Shorthand
npm i express

# Install multiple packages
npm install express mongoose dotenv

This:

  • Downloads the package to node_modules/ folder
  • Adds it to package.json under dependencies
  • Updates/creates package-lock.json

Development Dependencies

For tools used only during development:

# Install as dev dependency
npm install --save-dev nodemon
npm install -D eslint jest

# Short form
npm i -D nodemon

Adds to devDependencies in package.json:

{
  "dependencies": {
    "express": "^4.18.2"
  },
  "devDependencies": {
    "nodemon": "^3.0.1"
  }
}

Global Packages

For command-line tools you want available everywhere:

# Install globally
npm install -g nodemon
npm install -g typescript
npm install -g create-react-app

# Use them anywhere
nodemon app.js
tsc --version

Note: Avoid global installs when possible. Use npx instead (see below).

Using Installed Packages

After installing, require them in your code:

// app.js
const express = require('express');
const mongoose = require('mongoose');

const app = express();
// ... use the packages

Version Numbers

NPM uses semantic versioning (semver):

^4.18.2
│ │  │
│ │  └─ Patch (bug fixes)
│ └──── Minor (new features, backward compatible)  
└───── Major (breaking changes)

Version prefixes:

  • ^4.18.2 - Allow minor & patch updates (4.x.x)
  • ~4.18.2 - Allow only patch updates (4.18.x)
  • 4.18.2 - Exact version only
  • * or latest - Always latest (dangerous!)
{
  "dependencies": {
    "express": "^4.18.2",     // 4.18.2 to <5.0.0
    "lodash": "~4.17.21",     // 4.17.21 to <4.18.0
    "react": "18.2.0"         // Exactly 18.2.0
  }
}

NPM Scripts

Add custom commands to package.json:

{
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "test": "jest",
    "build": "webpack --mode production",
    "lint": "eslint ."
  }
}

Run them with:

npm run dev
npm run test
npm run build

# 'start' and 'test' are special - don't need 'run'
npm start
npm test

Common patterns:

{
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "test": "jest --coverage",
    "test:watch": "jest --watch",
    "lint": "eslint src/",
    "lint:fix": "eslint src/ --fix",
    "build": "webpack",
    "clean": "rm -rf dist"
  }
}

Package Files

package.json

  • Lists your dependencies
  • Defines scripts
  • Stores metadata
  • Committed to git

package-lock.json

  • Locks exact versions of all dependencies
  • Ensures consistent installs across machines
  • Committed to git

node_modules/

  • Contains all installed packages
  • Can be huge (100s of MB)
  • NOT committed to git
  • Add to .gitignore

Common NPM Commands

# Install all dependencies
npm install

# Install specific package
npm install package-name

# Install dev dependency
npm install -D package-name

# Install global package
npm install -g package-name

# Uninstall package
npm uninstall package-name

# Update packages
npm update

# Check for outdated packages
npm outdated

# View package info
npm info express

# Search for packages
npm search authentication

# List installed packages
npm list
npm list --depth=0  # Top-level only

# Clean cache (if issues)
npm cache clean --force

Using NPX

npx runs packages without installing them globally:

# Run package without installing
npx create-react-app my-app
npx cowsay "Hello!"

# Run local dev dependency
npx eslint .
npx jest

# Run specific version
npx create-react-app@latest my-app

Benefits:

  • No global pollution
  • Always use latest version
  • Try packages before installing

Finding Packages

Where to find packages:

Popular packages:

# Web frameworks
npm i express fastify koa

# Utilities
npm i lodash date-fns uuid

# Database
npm i mongoose pg mysql2

# Environment variables
npm i dotenv

# Testing
npm i -D jest mocha chai

# Validation
npm i joi zod yup

# Authentication
npm i jsonwebtoken bcrypt

# HTTP client
npm i axios node-fetch

Best Practices

DO:

  • Commit package.json and package-lock.json
  • Use npm ci in CI/CD (faster, stricter)
  • Review package size before installing
  • Keep dependencies updated
  • Use semantic versioning

DON’T:

  • Commit node_modules/ folder
  • Install everything globally
  • Ignore package-lock.json
  • Use * for versions

Example Project Structure

my-project/
├── node_modules/      # Dependencies (not in git)
├── src/
│   ├── index.js
│   └── utils/
├── package.json       # Dependencies & scripts
├── package-lock.json  # Locked versions
├── .gitignore         # Ignore node_modules
└── README.md

.gitignore:

node_modules/
.env
*.log

Troubleshooting

# Delete node_modules and reinstall
rm -rf node_modules package-lock.json
npm install

# Clear cache
npm cache clean --force

# Check npm configuration
npm config list

# Fix vulnerabilities
npm audit
npm audit fix

Summary

Command Purpose
npm init Create new project
npm install Install all dependencies
npm i package Install package
npm i -D package Install dev dependency
npm run script Run npm script
npx command Run package without install
npm update Update packages
npm uninstall pkg Remove package