What is Express.js and Why Use It?

Express.js is the most widely used Node.js web framework in the world. It provides a thin, flexible layer on top of Node.js’s built-in http module, adding the routing, middleware, and response utilities that every REST API needs โ€” without imposing a rigid architecture or philosophy on how you structure your project. In the MERN stack, Express is the technology that stands between your React frontend and your MongoDB database: it receives HTTP requests, processes them through middleware, queries the database, and returns JSON responses. In this lesson you will understand exactly what Express provides, why it exists, and how it fits into the bigger MERN picture.

The Problem Express Solves

As you saw in Chapter 3, building an HTTP API with raw Node.js requires a lot of repetitive, error-prone boilerplate. Every route needs manual URL parsing, every POST needs manual body stream collection, every response needs manual headers. Express packages all of this into a clean, composable API so you can focus on your application logic rather than HTTP plumbing.

Task Raw Node.js http Express
Define a GET route if (req.url === '/api/posts' && req.method === 'GET') app.get('/api/posts', handler)
Parse JSON body Collect stream chunks, concatenate, JSON.parse app.use(express.json())
Send JSON response res.writeHead(200); res.end(JSON.stringify(data)) res.json(data)
URL parameters Manual regex or string split on req.url req.params.id automatically parsed
Query strings Manual url.parse(req.url, true).query req.query.search automatically parsed
Serve static files Manual fs.readFile + mime type detection app.use(express.static('public'))
Reusable request processing No built-in concept app.use(middlewareFunction)
Note: Express is deliberately minimalist and unopinionated. It does not tell you which database to use, how to structure your folders, which template engine to pick, or how to handle authentication. This is a feature, not a limitation โ€” it means Express works equally well as a REST API server, a GraphQL server, a file upload handler, or a server-side rendering engine. You compose the behaviour you need by adding middleware.
Tip: Express 4 and Express 5 are both widely used. Express 5 (stable since late 2024) adds native async error handling โ€” errors thrown inside async route handlers are automatically passed to your error middleware without requiring try/catch in every handler. New MERN projects should use Express 5: npm install express@5. The API is almost identical to Express 4 so everything in this series applies to both.
Warning: Express is not a security framework. Out of the box it does not set security headers, limit request sizes, block SQL injection, or prevent brute-force attacks. You must add these protections yourself using packages like helmet (security headers), express-rate-limit (rate limiting), and express-validator (input validation). Always add these before deploying to production.

Express in the MERN Request Lifecycle

MERN Request Lifecycle โ€” Express's role highlighted

1.  User clicks "Load Posts" in the React app (browser)
2.  React component calls: axios.get('/api/posts')
3.  HTTP GET request leaves the browser โ†’ hits Express server

4.  Express receives the request
    โ”‚
    โ”œโ”€ cors middleware    โ†’ adds Access-Control-Allow-Origin header
    โ”œโ”€ helmet middleware  โ†’ adds security headers
    โ”œโ”€ express.json()    โ†’ parses request body (if POST/PUT)
    โ”œโ”€ auth middleware   โ†’ verifies JWT token if route is protected
    โ”‚
    โ””โ”€ Route handler: app.get('/api/posts', async (req, res) => {
         const posts = await Post.find();   โ† Mongoose queries MongoDB
         res.json({ success: true, data: posts });
       })

5.  MongoDB returns documents โ†’ Express formats as JSON
6.  HTTP response travels back to React
7.  React updates state โ†’ component re-renders with new posts

Express vs Other Node.js Frameworks

Framework Philosophy Best For Learning Curve
Express Minimalist, unopinionated REST APIs, custom architectures, learning Low
Fastify High performance, schema-based High-throughput APIs, TypeScript Medium
NestJS Angular-inspired, opinionated Large enterprise APIs, teams with Angular background High
Koa Next-gen Express (by same team), async-first Custom middleware stacks Medium
Hapi Configuration-driven, full-featured Enterprise APIs with built-in validation High

Key Express Concepts โ€” Preview

Concept What It Is Covered In
Application object const app = express() โ€” your server instance This chapter
Routes Map HTTP method + URL path to a handler function Chapters 5 & 6
Request object (req) Contains URL, params, query, body, headers This chapter
Response object (res) Methods to send data back: json, status, redirect This chapter
Middleware Functions that run between request and route handler Chapter 7
Router Mini Express app for organising related routes Chapter 6
Error handling Special 4-argument middleware for catching errors Chapter 7

Common Mistakes

Mistake 1 โ€” Calling express() multiple times

โŒ Wrong โ€” creating multiple app instances and trying to compose them:

const app1 = express();
const app2 = express();
app1.get('/api/posts', handler);
app2.get('/api/users', handler);
app1.listen(5000);
app2.listen(5000); // Error: port 5000 already in use

โœ… Correct โ€” one app per server. Use express.Router() to split routes into separate files while sharing the same app instance:

const app = express();
app.use('/api/posts', require('./routes/posts'));
app.use('/api/users', require('./routes/users'));
app.listen(5000);

Mistake 2 โ€” Confusing Express with a complete backend framework

โŒ Wrong โ€” expecting Express to provide authentication, validation, ORM, and email sending out of the box.

โœ… Correct โ€” Express is a routing and middleware framework. Everything else (auth, validation, email, database) comes from separate npm packages that you wire into Express via middleware. This is by design and is what makes Express so flexible.

Mistake 3 โ€” Using Express for CPU-intensive work

โŒ Wrong โ€” running image resizing, PDF generation, or heavy data processing synchronously inside Express route handlers โ€” this blocks all other incoming requests during processing.

โœ… Correct โ€” offload CPU work to worker threads, child processes, or a job queue. Express route handlers should be thin: validate input, query the database, return a response. Heavy work belongs elsewhere.

Quick Reference

Task Code
Install Express npm install express
Install Express 5 npm install express@5
Create app const app = express()
Add middleware app.use(middlewareFn)
Add JSON parser app.use(express.json())
Define route app.get('/path', (req, res) => res.json(data))
Start server app.listen(PORT, () => console.log('Running'))
Use sub-router app.use('/api/posts', postsRouter)

🧠 Test Yourself

A colleague says “Express handles authentication, database queries, and email sending automatically.” Is this correct?