Installation & Project Setup

1. Introduction

Before you can build anything with Node.js, you need a properly configured environment. This tutorial walks through installing Node.js, choosing the right package manager, and setting up a clean, production-ready project structure — including package.json, dependencies, linting, formatting, and TypeScript. đŸ› ī¸

Information

This guide is tool-agnostic where possible, but calls out differences between npm, Yarn, pnpm, and Bun whenever they matter.

2. Preparing Your Environment

System Requirements

  • Operating System: Windows 10+, macOS 11+, or a modern Linux distribution.
  • Disk space: At least 200MB free for Node.js itself; project dependencies add more.
  • RAM: 4GB minimum recommended for comfortable development.
  • Terminal access: Command Prompt, PowerShell, Terminal, or an integrated terminal in your editor.

Installing Node.js

There are several ways to install Node.js, and the right one depends on how much control you want over versions later on.

terminal

# Using Homebrew
brew install node

Download the official installer from nodejs.org, or use a package manager like winget:

terminal

winget install OpenJS.NodeJS.LTS

terminal

# Debian / Ubuntu
sudo apt update
sudo apt install nodejs npm

Tip

For day-to-day development, installing Node.js through a version manager (like nvm, covered below) is usually a better choice than a system-wide installer.

Node.js Release Types

Node.js publishes two parallel release lines simultaneously, each serving a different purpose.

Release TypePurposeStability
CurrentLatest features, released every 6 monthsNewer, less battle-tested
LTS (Long-Term Support)Stable releases recommended for productionHighly stable, supported for years

LTS vs Current

Every even-numbered major Node.js version (e.g. 18, 20, 22) eventually becomes an LTS release, receiving bug fixes and security patches for 30 months. Odd-numbered versions are short-lived and never promoted to LTS.

Best Practice

Use the LTS line for production applications. Reserve Current releases for experimenting with new language or runtime features.

Node Version Manager (nvm)

nvm lets you install and switch between multiple Node.js versions on the same machine — essential when different projects require different versions.

terminal

# Install nvm (macOS/Linux)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

# Install and use the latest LTS version
nvm install --lts
nvm use --lts

# Install a specific version
nvm install 20.11.0

# Switch between installed versions
nvm use 18

Hint

On Windows, use nvm-windows instead, since the original nvm relies on Unix shell scripting.

Verifying Installation

Once installed, confirm that both Node.js and npm are available on your PATH:

terminal

node --version
# v20.11.0

npm --version
# 10.2.4

3. Package Managers

Understanding npm

npm (Node Package Manager) is installed automatically with Node.js. It manages your project's dependencies, exposes scripts for common tasks, and connects you to the public npm registry — home to over a million packages. đŸ“Ļ

Understanding Package Managers

A package manager resolves, downloads, and organizes your project's dependencies (and their own sub-dependencies) so you don't have to manage them by hand. Several alternatives to npm have emerged, each with different trade-offs around speed, disk usage, and strictness.

  • Ships by default with Node.js
  • Largest install base, most documentation
  • Lockfile: package-lock.json
  • Created by Facebook to improve install speed and determinism
  • Offers Plug'n'Play mode to skip node_modules entirely
  • Lockfile: yarn.lock
  • Uses a content-addressable store to save disk space across projects
  • Strict by default — prevents accessing undeclared dependencies
  • Lockfile: pnpm-lock.yaml
  • All-in-one runtime, bundler, and package manager
  • Extremely fast installs due to a native implementation
  • Lockfile: bun.lockb

npm

terminal

npm install express
npm install --save-dev nodemon
npm run start

Yarn

terminal

yarn add express
yarn add --dev nodemon
yarn start

pnpm

terminal

pnpm add express
pnpm add -D nodemon
pnpm run start

Bun

terminal

bun add express
bun add -d nodemon
bun run start

Reference

All four package managers can install packages from the same npm registry — the difference lies in how they resolve, cache, and store those packages, not which packages are available.

4. Creating Your First Node.js Project

Project Structure

A clean, conventional project structure makes a codebase easier to navigate as it grows. A typical setup looks like this:

my-app
package.json
package-lock.json
.gitignore
.env
.eslintrc.json
.prettierrc
src
index.js
node_modules

Understanding package.json

package.json is the manifest file at the root of every Node.js project. It records the project's name, version, dependencies, scripts, and metadata.

package.json

{
  "name": "my-app",
  "version": "1.0.0",
  "description": "A sample Node.js project",
  "main": "src/index.js",
  "type": "module",
  "scripts": {
    "start": "node src/index.js",
    "dev": "nodemon src/index.js",
    "test": "vitest"
  },
  "dependencies": {
    "express": "^4.19.2"
  },
  "devDependencies": {
    "nodemon": "^3.1.0"
  }
}
FieldPurpose
name / versionIdentifies the package, especially if published
mainThe entry point when the package is required elsewhere
typeDetermines whether files use ES Modules or CommonJS
scriptsNamed shortcuts for common commands (e.g. npm run dev)
dependencies / devDependenciesPackages required at runtime vs. only during development

Understanding package-lock.json

While package.json declares version ranges (like ^4.19.2), package-lock.json records the exact version of every installed package — including sub-dependencies — ensuring everyone on a team installs identical dependency trees.

Warning

Always commit your lockfile to version control. Deleting it can lead to subtle version mismatches between environments.

Initializing a Project

terminal

mkdir my-app && cd my-app
npm init -y

The -y flag accepts all default values. Omit it if you'd like npm to prompt you interactively for each field.

Installing Dependencies

terminal

npm install express dotenv

This adds both packages under dependencies in package.json and downloads them into node_modules.

Installing Development Dependencies

Development dependencies are tools needed only while building the project — like test runners, linters, and formatters — not when it runs in production.

terminal

npm install --save-dev eslint prettier nodemon

Running Scripts

Scripts defined in package.json can be run with npm run <script-name>. A few conventional names — like start and test — can be run without the run keyword.

terminal

npm start
npm test
npm run dev

5. Writing and Running Code

Creating Your First Program

src/index.js

console.log('Hello, Node.js! 👋');

Running Node.js Applications

terminal

node src/index.js

Tip

Use node --watch src/index.js (available in modern Node.js versions) to automatically restart your app when files change, without installing nodemon.

The Node.js REPL

Typing node with no arguments opens the REPL (Read-Eval-Print Loop) — an interactive shell for experimenting with JavaScript directly in your terminal.

terminal

$ node
> 2 + 2
4
> const greet = (name) => `Hi, ${name}`;
undefined
> greet('Node')
'Hi, Node'
> .exit

Environment Variables

Environment variables let you keep configuration and secrets (like API keys) outside your codebase. The dotenv package loads variables from a .env file into process.env.

.env

PORT=3000
DATABASE_URL=postgres://localhost:5432/mydb

src/index.js

import 'dotenv/config';

console.log(process.env.PORT); // 3000

Danger

Never commit a .env file containing real secrets to version control — add it to .gitignore immediately.

6. Module Systems and Tooling

ES Modules Setup

ES Modules (import / export) are the modern, standardized module format shared with browser JavaScript. Enable them by setting "type": "module" in package.json.

package.json

{
  "type": "module"
}

src/math.js

export function add(a, b) {
  return a + b;
}

src/index.js

import { add } from './math.js';

console.log(add(2, 3)); // 5

CommonJS Setup

CommonJS (require / module.exports) is Node.js's original module system and remains the default when "type" is omitted or set to "commonjs".

src/math.js

function add(a, b) {
  return a + b;
}

module.exports = { add };

src/index.js

const { add } = require('./math.js');

console.log(add(2, 3)); // 5

Note

You generally shouldn't mix require and import within the same file. Pick one module system per project unless you have a specific interop need.

ESLint Setup

ESLint analyzes your code for potential errors and enforces consistent style rules.

terminal

npm install --save-dev eslint
npx eslint --init

eslint.config.json (simplified)

{
  "env": { "node": true, "es2022": true },
  "extends": "eslint:recommended",
  "rules": {
    "no-unused-vars": "warn",
    "no-console": "off"
  }
}

Prettier Setup

Prettier automatically formats your code for consistent style, complementing ESLint's focus on correctness.

terminal

npm install --save-dev prettier

.prettierrc

{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5"
}

TypeScript Setup

TypeScript adds static typing to JavaScript, catching many errors before code ever runs.

terminal

npm install --save-dev typescript @types/node
npx tsc --init

tsconfig.json (simplified)

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}

7. Ongoing Maintenance

Development Workflow

A typical daily workflow combines several of the tools covered above:

Write Code
Lint with ESLint
Format with Prettier
Run Locally
Run Tests
Commit & Push
node --watch
nodemon

Updating Dependencies

terminal

# See which packages are outdated
npm outdated

# Update within the version ranges in package.json
npm update

# Check for known vulnerabilities
npm audit
npm audit fix

Best Practice

Update dependencies incrementally and run your test suite after each batch, rather than upgrading everything at once — this makes it far easier to isolate breaking changes.

Common Installation Issues

IssueLikely Cause
command not found: nodeNode.js isn't installed, or isn't on your PATH
EACCES permission errorsGlobal npm packages installed without proper permissions
EADDRINUSEAnother process is already using the port your server needs
Version mismatch between machinesDifferent Node.js or lockfile versions across environments

Troubleshooting

  1. Confirm your Node.js version with node --version and compare against your project's requirements.
  2. Delete node_modules and your lockfile, then reinstall dependencies from scratch.
  3. Check for conflicting global installs versus a version manager like nvm.
  4. Search the exact error message — most Node.js errors are well-documented online.

terminal

rm -rf node_modules package-lock.json
npm install

8. Summary

Best Practices

  • Use a version manager like nvm instead of a single global Node.js install.
  • Prefer LTS releases for production applications.
  • Always commit your lockfile to version control.
  • Separate dependencies from devDependencies correctly.
  • Set up ESLint and Prettier early, before a codebase grows large.
  • Keep secrets in .env files, never in source code.

Summary

A solid Node.js setup starts with the right installation strategy, a well-chosen package manager, and a clean project structure governed by package.json. Layering in linting, formatting, and optionally TypeScript establishes a foundation that scales comfortably as your project grows. ✅

Summary

With Node.js installed, your package manager chosen, and your project scaffolded, you're ready to start building real applications — servers, APIs, and beyond. 🚀