Difficulty: Beginner
What is Express.js and why is it the most popular Node.js framework? Show the basic setup and key features.
Express.js is a minimal, unopinionated web framework for Node.js that provides a thin layer of fundamental features on top of the http module. It simplifies routing, middleware handling, request/response processing, and template rendering.
Express enhances the native req and res objects with helper methods like req.params, req.query, req.body (with middleware), res.json(), res.status(), res.send(), and res.redirect(). These save significant boilerplate compared to the raw http module.
The framework follows a middleware-based architecture where each request passes through a pipeline of functions. This makes it easy to add features like body parsing, authentication, logging, and error handling as composable layers.
Express Router allows you to organize routes into modular groups. Each router acts as a mini-application with its own middleware and routes, which can be mounted at a specific path prefix. This is how large applications stay organized.
const express = require('express');
const app = express();
// Built-in middleware
app.use(express.json()); // Parse JSON bodies
app.use(express.urlencoded({ extended: true })); // Parse form data
app.use(express.static('public')); // Serve static files
// Route handlers
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.get('/api/users', (req, res) => {
// req.query contains URL parameters: /api/users?page=2&limit=10
const { page = 1, limit = 10 } = req.query;
res.json({
page: Number(page),
limit: Number(limit),
users: [{ id: 1, name: 'Alice' }]
});
});
app.post('/api/users', (req, res) => {
// req.body available thanks to express.json()
const { name, email } = req.body;
res.status(201).json({ id: 1, name, email });
});
app.listen(3000, () => console.log('Server on port 3000'));
express.json() parses request bodies. Route methods match HTTP verbs. res.json() automatically sets Content-Type and stringifies.
// routes/users.js
const express = require('express');
const router = express.Router();
// Routes are relative to the mount point
router.get('/', (req, res) => {
res.json({ users: [] });
});
router.get('/:id', (req, res) => {
res.json({ user: { id: req.params.id } });
});
router.post('/', (req, res) => {
res.status(201).json({ user: req.body });
});
router.put('/:id', (req, res) => {
res.json({ updated: req.params.id });
});
router.delete('/:id', (req, res) => {
res.status(204).end();
});
module.exports = router;
// index.js
const userRoutes = require('./routes/users');
const productRoutes = require('./routes/products');
app.use('/api/users', userRoutes);
app.use('/api/products', productRoutes);
Routers group related endpoints. Each router only defines paths relative to its mount point. This is the standard pattern for organizing Express apps.
const express = require('express');
const app = express();
app.get('/examples', (req, res) => {
// Send JSON
res.json({ key: 'value' });
// Set status + JSON
res.status(404).json({ error: 'Not found' });
// Send text/HTML
res.send('<h1>Hello</h1>');
// Send file
res.sendFile('/path/to/file.pdf');
// Redirect
res.redirect(301, '/new-location');
// Set custom headers
res.set('X-Custom-Header', 'value');
// Send status only
res.sendStatus(204); // No Content
// Download
res.download('/path/to/file.pdf', 'report.pdf');
});
// Chaining
app.get('/chain', (req, res) => {
res
.status(200)
.set('Cache-Control', 'public, max-age=3600')
.json({ cached: true });
});
Express provides many response helpers. res.json() handles serialization. res.status() is chainable. res.sendFile() handles streaming and headers automatically.
Express, app.use, Router, Request, Response