If Node.js is the “founding father” of JavaScript on the server, then Express is the “pioneer” of Node.js web frameworks. Although many frameworks have emerged since, Express remains the top choice for Node.js developers.
What is Express?#
Express is the most classic web framework in the Node.js ecosystem, created by TJ Holowaychuk in 2009. Its core characteristic is: simple, flexible, minimalist.
Understanding Through Analogy#
| Aspect | Express | NestJS |
|---|---|---|
| Style | Minimalist | Enterprise |
| Constraints | Almost none | Convention first |
| Learning curve | Flat | Relatively steep |
| Flexibility | Extremely high | Medium |
| Like | LEGO free-form building | LEGO official set |
Express gives you maximum freedom—you can organize code your own way.
Core Features#
1. Simple API: Five Minutes to Get Started#
Express’s API is extremely simple:
const express = require('express');
const app = express();
const port = 3000;
// Routes
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.get('/api/users', (req, res) => {
res.json([
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
]);
});
// Start server
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});2. Routing System: Clear and Intuitive#
Express’s routing is very intuitive:
// Basic routes
app.get('/users', (req, res) => {
res.send('Get user list');
});
app.post('/users', (req, res) => {
res.send('Create user');
});
app.put('/users/:id', (req, res) => {
res.send(`Update user ${req.params.id}`);
});
app.delete('/users/:id', (req, res) => {
res.send(`Delete user ${req.params.id}`);
});
// Route parameters
app.get('/users/:id/posts/:postId', (req, res) => {
res.json({
userId: req.params.id,
postId: req.params.postId
});
});
// Query parameters
app.get('/search', (req, res) => {
res.json(req.query); // ?q=keyword&page=1
});3. Middleware: The Soul of Express#
Middleware is the core concept of Express—a function that has access to request and response objects.
// Middleware function
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next(); // Call the next middleware
};
// Application-level middleware
app.use(logger);
// Route-level middleware
const auth = (req, res, next) => {
if (req.headers.authorization) {
next();
} else {
res.status(401).send('Unauthorized');
}
};
app.get('/protected', auth, (req, res) => {
res.send('Protected route');
});Common middleware:
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const bodyParser = require('body-parser');
app.use(cors()); // Cross-origin resource sharing
app.use(helmet()); // Security headers
app.use(morgan('dev')); // Logging
app.use(bodyParser.json()); // Parse JSON
app.use(bodyParser.urlencoded({ extended: true })); // Parse form data
4. Request Object: Getting Client Data#
app.get('/demo', (req, res) => {
// Route parameters: /demo/123
console.log(req.params.id);
// Query parameters: /demo?id=123
console.log(req.query.id);
// Request headers
console.log(req.headers.authorization);
// Request body (needs body-parser)
console.log(req.body.name);
// Cookies
console.log(req.cookies.token);
});5. Response Object: Returning Data#
app.get('/responses', (req, res) => {
// Send string
res.send('Hello');
// Send JSON
res.json({ message: 'Hello' });
// Send file
res.download('/path/to/file');
// Redirect
res.redirect('/other-page');
// Set status code
res.status(201).json({ created: true });
});6. Error Handling#
// Synchronous error handling
app.get('/error', (req, res) => {
throw new Error('Something went wrong!');
});
// Asynchronous error handling
app.get('/async-error', async (req, res, next) => {
try {
const data = await fetchData();
res.json(data);
} catch (error) {
next(error); // Pass to error handling middleware
}
});
// Error handling middleware (must be at the end)
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Server error' });
});7. Router: Modularizing Routes#
// users.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('User list');
});
router.get('/:id', (req, res) => {
res.send(`User ${req.params.id}`);
});
module.exports = router;
// app.js
const usersRouter = require('./users');
app.use('/users', usersRouter);Why is Express So Popular?#
1. Simple and Flexible#
Express’s design philosophy is “minimalism”:
- Core is very small
- Features extend through middleware
- No forced code structure
2. Mature Ecosystem#
Express has the most mature Node.js ecosystem:
- Rich middleware
- Complete documentation
- Large community
- Many tutorials
3. Foundation for Most Node.js Frameworks#
Many frameworks are built on Express:
- NestJS (can use Express adapter)
- Next.js (early versions)
- Feathers
- Sails.js
4. Perfect for Rapid Development#
For small projects and prototypes, Express is the best choice:
- Quick to learn
- Less code
- High flexibility
Use Cases#
| Scenario | Suitability | Notes |
|---|---|---|
| Small web apps | ⭐⭐⭐⭐⭐ | Simple and flexible |
| REST API | ⭐⭐⭐⭐⭐ | Fast development |
| Prototyping | ⭐⭐⭐⭐⭐ | Rapid iteration |
| Microservices | ⭐⭐⭐⭐ | Lightweight and fast |
| Medium-large apps | ⭐⭐⭐ | Needs good code organization |
| Enterprise apps | ⭐⭐ | NestJS recommended |
Express vs Native Node.js#
// Native Node.js
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/users' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify([{ id: 1 }]));
}
});
server.listen(3000);
// Express
const express = require('express');
const app = express();
app.get('/users', (req, res) => {
res.json([{ id: 1 }]);
});
app.listen(3000);Express greatly simplifies Node.js HTTP handling.
Learning Path#
Beginner (1 week)#
- Master Node.js basics
- Understand Express basics
- Learn routing and middleware
- Master request and response objects
Intermediate (1-2 weeks)#
- Deep dive into middleware principles
- Master error handling
- Learn to use Router for modularization
- Master template engines (optional)
Advanced (continuous learning)#
- Performance optimization
- Security best practices
- Database integration
- Understand Express internals
Common Middleware#
| Middleware | Purpose |
|---|---|
| cors | Cross-origin support |
| helmet | Security headers |
| morgan | Logging |
| body-parser | Request body parsing |
| cookie-parser | Cookie parsing |
| express-session | Sessions |
| multer | File uploads |
| compression | Compression |
Comparison with Other Node.js Frameworks#
| Feature | Express | Koa | Fastify | NestJS |
|---|---|---|---|---|
| Simplicity | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| Performance | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| Async support | Callbacks | async/await | async/await | async/await |
| Middleware | Traditional | Onion model | Plugins | Guards/interceptors |
| Learning curve | Flat | Flat | Flat | Relatively steep |
Simply put:
- Express: Classic and stable, mature ecosystem
- Koa: More modern, onion model
- Fastify: Highest performance
- NestJS: Enterprise architecture
Summary#
Express is the “evergreen tree” of the Node.js ecosystem:
- Simple API—Five minutes to get started
- Middleware system—Flexible extensions
- Clear routing—Easy to understand
- Mature ecosystem—Abundant resources
- Highly flexible—Customize as needed
Although “new frameworks” keep emerging, Express remains the foundation of Node.js development. Once you learn Express, you can easily transition to other frameworks.
Next up: We’ve covered backend frameworks. Now let’s move to mobile development. Flutter is Google’s cross-platform UI framework, known for high-performance rendering and “write once, run anywhere.” Let’s dive into this “new species of UI frameworks” in the next article.
