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.
Prerequisites
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.
- Download the Windows Installer (.msi) from nodejs.org
- Run the installer and follow the installation wizard
- 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)
bashPORT=3000 NODE_ENV=development
2. Configuration (src/config/index.js)
javascriptrequire("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)
javascriptconst 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)
javascriptconst 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)
javascriptconst 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)
javascriptconst 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)
javascriptconst 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)
javascriptmodule.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
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
- 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
Next Lesson
Routing and Middleware in Depth