beginner
backend

Setting Up Express Development Environment

Installing Node.js, npm, and creating your first Express.js project with proper structure

express fundamentals
15 min read

Setting Up Your Development Environment

Before you can start building with Express.js, you need to set up your development environment properly. This lesson will guide you through installing the necessary tools and creating a well-structured project.


Installing Node.js and npm

Node.js is the runtime that allows Express to run. npm (Node Package Manager) comes bundled with it.

Step 1: Download Node.js

Visit nodejs.org and download the LTS (Long Term Support) version.

  1. Download the Windows Installer (.msi) from nodejs.org
  2. Run the installer and follow the installation wizard
  3. Verify installation by opening PowerShell and running:

node --version


npm --version


Creating Your First Express Project

Step 1: Initialize the Project

bash
# Create project directory mkdir my-express-api cd my-express-api # Initialize npm project npm init -y

Step 2: Install Express and Dependencies

bash
# Core dependencies npm install express cors helmet morgan dotenv # Development dependencies npm install -D nodemon

Package Breakdown

express
The web framework itself
cors
Enable Cross-Origin Resource Sharing
helmet
Security middleware for HTTP headers
morgan
HTTP request logger
dotenv
Load environment variables from .env file
nodemon
Auto-restart server on file changes (dev only)

Step 3: Update package.json Scripts

json
{ "name": "my-express-api", "version": "1.0.0", "main": "src/index.js", "scripts": { "start": "node src/index.js", "dev": "nodemon src/index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", "helmet": "^7.1.0", "morgan": "^1.10.0" }, "devDependencies": { "nodemon": "^3.0.2" } }

Project Structure

A well-organized project structure is crucial for maintainability:

Recommended Folder Structure

my-express-api/
├── src/
│   ├── index.js          # Entry point
│   ├── app.js            # Express app configuration
│   ├── config/
│   │   └── index.js      # Configuration settings
│   ├── routes/
│   │   ├── index.js      # Route aggregator
│   │   └── users.js      # User routes
│   ├── controllers/
│   │   └── users.js      # User controller logic
│   ├── middleware/
│   │   ├── auth.js       # Authentication middleware
│   │   └── error.js      # Error handling middleware
│   ├── models/
│   │   └── User.js       # User model (for database)
│   ├── services/
│   │   └── users.js      # Business logic
│   └── utils/
│       └── helpers.js    # Utility functions
├── .env                  # Environment variables
├── .env.example          # Environment template
├── .gitignore
├── package.json
└── README.md

Setting Up the Files

1. Environment Variables (.env)

bash
PORT=3000 NODE_ENV=development

2. Configuration (src/config/index.js)

javascript
require("dotenv").config() module.exports = { port: process.env.PORT || 3000, nodeEnv: process.env.NODE_ENV || "development", isProduction: process.env.NODE_ENV === "production", }

3. Express App (src/app.js)

javascript
const express = require("express") const cors = require("cors") const helmet = require("helmet") const morgan = require("morgan") const routes = require("./routes") const errorHandler = require("./middleware/error") const config = require("./config") const app = express() // Security middleware app.use(helmet()) // CORS app.use(cors()) // Request logging if (!config.isProduction) { app.use(morgan("dev")) } // Body parsers app.use(express.json()) app.use(express.urlencoded({ extended: true })) // API routes app.use("/api", routes) // Health check app.get("/health", (req, res) => { res.json({ status: "ok", timestamp: new Date().toISOString() }) }) // 404 handler app.use((req, res) => { res.status(404).json({ error: "Route not found" }) }) // Error handling app.use(errorHandler) module.exports = app

4. Entry Point (src/index.js)

javascript
const app = require("./app") const config = require("./config") const server = app.listen(config.port, () => { console.log(`🚀 Server running on http://localhost:${config.port}`) console.log(`📝 Environment: ${config.nodeEnv}`) }) // Graceful shutdown process.on("SIGTERM", () => { console.log("SIGTERM received. Shutting down gracefully...") server.close(() => { console.log("Server closed") process.exit(0) }) })

5. Routes (src/routes/index.js)

javascript
const express = require("express") const usersRoutes = require("./users") const router = express.Router() router.use("/users", usersRoutes) module.exports = router

6. User Routes (src/routes/users.js)

javascript
const express = require("express") const usersController = require("../controllers/users") const router = express.Router() router.get("/", usersController.getAll) router.get("/:id", usersController.getById) router.post("/", usersController.create) router.patch("/:id", usersController.update) router.delete("/:id", usersController.remove) module.exports = router

7. User Controller (src/controllers/users.js)

javascript
const usersService = require("../services/users") exports.getAll = async (req, res, next) => { try { const users = await usersService.findAll() res.json(users) } catch (error) { next(error) } } exports.getById = async (req, res, next) => { try { const user = await usersService.findById(req.params.id) if (!user) { return res.status(404).json({ error: "User not found" }) } res.json(user) } catch (error) { next(error) } } exports.create = async (req, res, next) => { try { const user = await usersService.create(req.body) res.status(201).json(user) } catch (error) { next(error) } } exports.update = async (req, res, next) => { try { const user = await usersService.update(req.params.id, req.body) if (!user) { return res.status(404).json({ error: "User not found" }) } res.json(user) } catch (error) { next(error) } } exports.remove = async (req, res, next) => { try { const success = await usersService.remove(req.params.id) if (!success) { return res.status(404).json({ error: "User not found" }) } res.status(204).send() } catch (error) { next(error) } }

8. Error Middleware (src/middleware/error.js)

javascript
module.exports = (err, req, res, next) => { console.error(err.stack) const statusCode = err.statusCode || 500 const message = err.message || "Internal Server Error" res.status(statusCode).json({ error: message, ...(process.env.NODE_ENV === "development" && { stack: err.stack }), }) }

Running the Server

Start Development Server

npm run dev

Your Express server should now be running at http://localhost:3000. Visit http://localhost:3000/health to check if it's working!


VS Code Extensions for Express

Recommended Extensions
  • REST Client— Test APIs directly in VS Code
  • Thunder Client— Lightweight REST API client
  • ESLint— JavaScript linting
  • Prettier— Code formatting
  • DotENV— .env file syntax highlighting

Next Steps

Continue Learning
With your development environment set up, you're ready to learn about advanced routing and middleware patterns!

Next Lesson

Routing and Middleware in Depth