Express.js Installation & Setup

Node.js setup, Express installation, first app, and project structure

Node.js npm First App

Table of Contents

1. Node.js Setup and Installation

What is Node.js?

Node.js is a JavaScript runtime built on Chrome's V8 engine that allows you to run JavaScript on the server-side. Express.js runs on top of Node.js.

Installation Methods

Method 1: Official Installer (Recommended for Beginners)

Windows:

  • Visit nodejs.org
  • Download the LTS (Long Term Support) version
  • Run the installer (.msi file)
  • Follow installation wizard (default settings are fine)
  • Restart your computer

macOS:

  • Download the .pkg installer from nodejs.org
  • Run the installer
  • Follow the installation prompts

Linux (Ubuntu/Debian):

Bashcurl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt-get install -y nodejs

Method 2: Using Node Version Manager (NVM) - Advanced

Bash# Install NVM curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash # Restart terminal, then install Node nvm install --lts nvm use --lts

Verify Installation

Open your terminal/command prompt and run:

Bash# Check Node.js version node --version # Should output: v18.x.x or higher # Check npm version npm --version # Should output: 9.x.x or higher # Check Node.js installation path (optional) where node # Windows which node # macOS/Linux

Understanding npm (Node Package Manager)

npm comes automatically with Node.js. It's used to:

  • Install packages (like Express)
  • Manage project dependencies
  • Run scripts
Bash# Common npm commands npm --version # Check npm version npm help # Get help npm list # List installed packages npm update # Update packages npm uninstall <package> # Remove a package

2. Express.js Installation

Step-by-Step Installation

Step 1: Create Project Directory

Bash# Create new folder for your project mkdir my-express-app cd my-express-app # Or use an existing folder cd your-project-folder

Step 2: Initialize npm Project

Bash# Initialize with default settings npm init -y # Or initialize interactively (answer prompts) npm init

This creates a package.json file:

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

Step 3: Install Express

Bash# Install Express and add to dependencies npm install express # Or install with specific version npm install express@4.18.2 # Install as development dependency (not common for Express) npm install express --save-dev

Step 4: Verify Installation

After installation, check package.json:

JSON{ "dependencies": { "express": "^4.18.2" } }

You'll also see:

  • node_modules/ folder (contains Express and its dependencies)
  • package-lock.json (locks dependency versions)

What Gets Installed?

Express has several key dependencies:

Dependency Treeexpress@4.18.2 ├── accepts@1.3.8 ├── body-parser@1.20.1 ├── content-disposition@0.5.4 ├── cookie-parser@1.4.6 ├── cookie-signature@1.0.6 ├── debug@2.6.9 ├── depd@2.0.0 ├── encodeurl@1.0.2 ├── escape-html@1.0.3 ├── etag@1.8.1 ├── finalhandler@1.2.0 ├── fresh@0.5.2 ├── merge-descriptors@1.0.1 ├── methods@1.1.2 ├── on-finished@2.4.1 ├── parseurl@1.3.3 ├── path-to-regexp@0.1.7 ├── proxy-addr@2.0.7 ├── qs@6.11.0 ├── range-parser@1.2.1 ├── safe-buffer@5.2.1 ├── send@0.18.0 ├── serve-static@1.15.0 ├── setprototypeof@1.2.0 ├── statuses@2.0.1 ├── type-is@1.6.18 ├── utils-merge@1.0.1 └── vary@1.1.2

Alternative Installation Methods

Global Installation (not recommended for Express):

Bashnpm install -g express

Using yarn (alternative to npm):

Bash# Install yarn first npm install -g yarn # Then install Express yarn add express

3. Your First Express Application

Creating the Entry File

Create app.js (or server.js or index.js) in your project root:

JavaScript — app.js// app.js - Your first Express application // Import Express module const express = require('express'); // Create an Express application const app = express(); // Define the port number const PORT = process.env.PORT || 3000; // Basic route - Homepage app.get('/', (req, res) => { res.send('Hello World! Welcome to my first Express app!'); }); // Another route - About page app.get('/about', (req, res) => { res.send('This is the about page. Learning Express.js!'); }); // API route - Returns JSON app.get('/api/users', (req, res) => { res.json({ success: true, users: [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' } ] }); }); // Dynamic route with parameter app.get('/users/:id', (req, res) => { const userId = req.params.id; res.send(`Viewing profile of user: ${userId}`); }); // Start the server app.listen(PORT, () => { console.log('Server is running!'); console.log(`Local: http://localhost:${PORT}`); console.log(`API: http://localhost:${PORT}/api/users`); console.log('Press Ctrl+C to stop the server'); });

Running Your Application

Method 1: Direct Node Command

Bashnode app.js

Method 2: Using npm Scripts (Better)

Add this to package.json:

JSON{ "scripts": { "start": "node app.js", "dev": "nodemon app.js" } }

Then run:

Bashnpm start # For production npm run dev # For development (with auto-restart)

Method 3: Using Nodemon (Auto-restart on changes)

Bash# Install nodemon globally npm install -g nodemon # Or as dev dependency npm install --save-dev nodemon # Run with nodemon nodemon app.js

Testing Your Application

Open your browser and visit:

  • http://localhost:3000/ — Hello World message
  • http://localhost:3000/about — About page
  • http://localhost:3000/api/users — JSON response
  • http://localhost:3000/users/123 — Dynamic route

Or use curl in terminal:

Bashcurl http://localhost:3000/ curl http://localhost:3000/api/users curl http://localhost:3000/users/456

Common Issues and Solutions

Error: "Port already in use"

Bash# Find process using port 3000 (Windows) netstat -ano | findstr :3000 taskkill /PID <PID> /F # macOS/Linux lsof -i :3000 kill -9 <PID>

Error: "Cannot find module 'express'"

Bash# Reinstall Express npm install express

Error: "node is not recognized" — Node.js is not installed or not in PATH. Restart terminal or reinstall Node.js.

4. Understanding Folder Structure

Basic Project Structure (Getting Started)

Folder Structuremy-express-app/ │ ├── node_modules/ # Dependencies (don't edit manually) │ ├── express/ │ ├── accepts/ │ └── ... (other dependencies) │ ├── app.js # Main application file ├── package.json # Project configuration ├── package-lock.json # Locked dependency versions ├── .gitignore # Git ignore file └── README.md # Project documentation

Standard Express Project Structure

Folder Structureexpress-project/ │ ├── node_modules/ │ ├── public/ # Static files (served directly) │ ├── css/ │ ├── js/ │ ├── images/ │ └── uploads/ │ ├── views/ # Template files │ ├── layouts/ │ ├── partials/ │ └── pages/ │ ├── routes/ # Route definitions ├── controllers/ # Business logic ├── models/ # Database models ├── middleware/ # Custom middleware ├── config/ # Configuration files ├── utils/ # Helper functions ├── services/ # Business services ├── tests/ # Test files ├── logs/ # Application logs │ ├── .env ├── .gitignore ├── app.js ├── server.js ├── package.json └── README.md

File and Folder Purposes

File/FolderPurpose
node_modules/All installed npm packages (auto-generated)
public/Static files accessible to clients (CSS, JS, images)
views/Template files for rendering HTML
routes/Route definitions (URL endpoints)
controllers/Business logic and request handling
models/Database schema and data models
middleware/Custom Express middleware functions
config/Configuration files (database, auth, etc.)
utils/Reusable helper functions
app.jsExpress app configuration and middleware setup
server.jsServer startup and port listening
.envEnvironment variables (API keys, passwords)

Creating the Structure

Bash# Create basic folder structure mkdir -p public/{css,js,images,uploads} mkdir -p views/{layouts,partials,pages} mkdir -p routes controllers models middleware config utils services tests/{unit,integration,e2e} mkdir logs # Create initial files touch app.js server.js .env .gitignore README.md touch routes/index.js touch controllers/userController.js touch models/User.js touch middleware/logger.js touch config/database.js

5. Project Organization Best Practices

Configuration Files

.gitignore (what NOT to commit to git):

gitignore# Dependencies node_modules/ package-lock.json yarn.lock # Environment variables .env .env.local .env.production # Logs logs/ *.log npm-debug.log* # OS files .DS_Store Thumbs.db # IDE files .vscode/ .idea/ *.swp # Build files dist/ build/ # Uploads public/uploads/

.env (environment variables):

env# Server Configuration PORT=3000 NODE_ENV=development # Database DB_HOST=localhost DB_PORT=27017 DB_NAME=myapp DB_USER=admin DB_PASSWORD=secret # API Keys API_KEY=your_api_key_here SECRET_KEY=your_secret_key # Authentication JWT_SECRET=your_jwt_secret JWT_EXPIRE=7d

package.json (with helpful scripts):

JSON{ "name": "express-app", "version": "1.0.0", "description": "My Express.js application", "main": "server.js", "scripts": { "start": "node server.js", "dev": "nodemon server.js", "test": "jest", "lint": "eslint .", "format": "prettier --write .", "seed": "node seed.js" }, "keywords": ["express", "nodejs", "api"], "author": "Your Name", "license": "MIT", "dependencies": { "express": "^4.18.2", "dotenv": "^16.0.3" }, "devDependencies": { "nodemon": "^2.0.20", "jest": "^29.3.1" } }

Example: Complete App Structure with Code

server.js (entry point):

JavaScriptconst app = require('./app'); const config = require('./config/environment'); const PORT = config.PORT || 3000; app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); console.log(`Environment: ${config.NODE_ENV}`); console.log(`http://localhost:${PORT}`); });

app.js (Express configuration):

JavaScriptconst express = require('express'); const path = require('path'); const config = require('./config/environment'); const indexRoutes = require('./routes/index'); const userRoutes = require('./routes/users'); const apiRoutes = require('./routes/api'); const logger = require('./middleware/logger'); const errorHandler = require('./middleware/errorHandler'); const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(express.static(path.join(__dirname, 'public'))); app.use(logger); app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); app.use('/', indexRoutes); app.use('/users', userRoutes); app.use('/api', apiRoutes); app.use((req, res) => { res.status(404).render('error', { message: 'Page not found' }); }); app.use(errorHandler); module.exports = app;

routes/index.js:

JavaScriptconst express = require('express'); const router = express.Router(); const homeController = require('../controllers/homeController'); router.get('/', homeController.getHomePage); router.get('/about', homeController.getAboutPage); router.get('/contact', homeController.getContactPage); module.exports = router;

controllers/homeController.js:

JavaScriptexports.getHomePage = (req, res) => { res.render('pages/index', { title: 'Home', message: 'Welcome to our website' }); }; exports.getAboutPage = (req, res) => { res.render('pages/about', { title: 'About Us', company: 'Express Inc.' }); }; exports.getContactPage = (req, res) => { res.render('pages/contact', { title: 'Contact Us' }); };

Development vs Production Setup

Development (NODE_ENV=development)

  • Use nodemon for auto-restart
  • Enable detailed error messages
  • Log verbose output
  • Use local databases

Production (NODE_ENV=production)

  • Use process managers (PM2)
  • Enable compression
  • Set security headers
  • Use environment-specific configs

Package.json Scripts Examples

JSON{ "scripts": { "start": "node server.js", "dev": "nodemon server.js", "prod": "NODE_ENV=production node server.js", "pm2-start": "pm2 start server.js --name my-app", "pm2-stop": "pm2 stop my-app", "pm2-restart": "pm2 restart my-app", "debug": "node --inspect server.js", "lint": "eslint . --fix", "test": "jest --coverage", "clean": "rm -rf node_modules package-lock.json && npm install" } }

Essential npm Packages for Project Setup

Bash# Development dependencies npm install --save-dev nodemon # Auto-restart server npm install --save-dev eslint # Code linting npm install --save-dev prettier # Code formatting npm install --save-dev jest # Testing framework # Production dependencies npm install express # Web framework npm install dotenv # Environment variables npm install cors # CORS support npm install helmet # Security headers npm install morgan # HTTP logging npm install compression # Response compression

Sample README.md

Markdown# Express.js Application ## Setup Instructions 1. Clone repository 2. Run `npm install` 3. Copy `.env.example` to `.env` and update values 4. Run `npm run dev` for development 5. Run `npm start` for production ## Project Structure - `public/` - Static assets - `views/` - Template files - `routes/` - Route definitions - `controllers/` - Business logic - `models/` - Database models - `middleware/` - Custom middleware - `config/` - Configuration files ## Available Scripts - `npm start` - Start production server - `npm run dev` - Start development server with auto-reload - `npm test` - Run tests - `npm run lint` - Lint code ## Environment Variables Create `.env` file with: PORT=3000 NODE_ENV=development

Quick Start Template

package.json

JSON{ "name": "express-starter", "version": "1.0.0", "description": "Express.js starter template", "main": "server.js", "scripts": { "start": "node server.js", "dev": "nodemon server.js" }, "dependencies": { "express": "^4.18.2", "dotenv": "^16.0.3" }, "devDependencies": { "nodemon": "^2.0.20" } }

.env

envPORT=3000 NODE_ENV=development

server.js

JavaScriptconst express = require('express'); require('dotenv').config(); const app = express(); const PORT = process.env.PORT || 3000; app.use(express.json()); app.get('/', (req, res) => { res.json({ message: 'Express server is running!' }); }); app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`); });

Installation Commands:

Bash# Create project mkdir my-express-app && cd my-express-app # Create files npm init -y npm install express dotenv npm install --save-dev nodemon # Create .env and server.js (copy above content) # Run the app npm run dev

Troubleshooting Common Issues

IssueSolution
npm command not foundReinstall Node.js
Cannot find moduleRun npm install again
EACCES: permission deniedUse sudo (Linux/Mac) or run as admin (Windows)
Port already in useChange PORT in .env or kill process using port
Module not found after moving filesClear cache: npm cache clean --force
Express not recognizedInstall locally: npm install express

Next Steps After Setup

Now that you have Express installed and your project structured:

  • Add more routes and controllers
  • Implement middleware (logging, auth)
  • Connect a database (MongoDB, PostgreSQL)
  • Add template engine (EJS, Pug)
  • Implement error handling
  • Add validation (express-validator)
  • Write tests
  • Deploy to cloud (Heroku, Render, Vercel)