Express.js Installation & Setup
Node.js setup, Express installation, first app, and project structure
Node.js
npm
First App
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/Folder | Purpose |
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.js | Express app configuration and middleware setup |
server.js | Server startup and port listening |
.env | Environment 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
| Issue | Solution |
| npm command not found | Reinstall Node.js |
| Cannot find module | Run npm install again |
| EACCES: permission denied | Use sudo (Linux/Mac) or run as admin (Windows) |
| Port already in use | Change PORT in .env or kill process using port |
| Module not found after moving files | Clear cache: npm cache clean --force |
| Express not recognized | Install 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)