Express.js has finally published version 5.0 on October 15, 2024. This marks a significant milestone, coming after a 10-year wait since the initial pull request was opened in July 2014. This major release brings a series of important updates, optimizations, and removals, aiming to improve performance and streamline development for future Node.js projects.
Express.js 5.0 brings a series of significant updates, optimizations, and removals. While it’s still in beta, this version is shaping up to improve performance and streamline development for future Node.js projects.
Express.js 5.0 requires Node.js 18 or higher, so anyone still on older versions will need to upgrade.
Installing Express.js 5.0
To try out Express.js 5.0, run:
npm install --save express@next
Make sure to check the latest version of Express.js on NPM. Now, let’s explore what’s new and what updates you’ll need to make.
What’s Changed in Express.js 5.0
In this section, I’ll walk through the most important changes in Express.js 5.0 and provide practical tips to help you smoothly transition your existing apps to the new version.
Removed Methods and Properties
Several legacy methods have been removed, and you’ll need to refactor your code if you use any of the following:
-
app.del()
– Now replaced withapp.delete()
to align with modern JavaScript standards. It’s time to update all instances whereapp.del()
was used. -
app.param(fn)
– This helper for modifying app.param(name, fn)
is completely gone. It’s been deprecated for a while, and now it’s time to remove it for good. -
Pluralized methods – Functions like
req.acceptsCharset()
are now pluralized, e.g.,req.acceptsCharsets()
. It’s a small change, but essential for keeping your code compatible. -
req.param(name)
– This method has been removed. Instead, you now need to explicitly usereq.params
,req.body
, orreq.query
to retrieve the parameters.
Updates to Path Route Matching
Express 5 introduces changes in how path route matching works. If your app relies on complex route patterns, you need to take note of these changes:
-
You can now use
?
,*
, and+
parameter modifiers. -
RegExp syntax is stricter, so paths like
/foo*
must be updated to/foo(.*)
For example, if your code previously matched routes like this:
app.get('/user*', (req, res) => res.send('User'));
You’ll need to update it to:
app.get('/user(.*)', (req, res) => res.send('User'));
Promise Rejection Handling
Express.js 5 makes it easier to handle errors in async middleware and routes. Rejected promises are automatically passed to the error-handling middleware. This simplifies error management when working with async
functions.
For example:
app.get('/route', async (req, res, next) => {
const result = await someAsyncFunction();
res.send(result);
});
If someAsyncFunction()
throws an error, it will automatically be caught by the error handler, and you no longer need to manually call next(err)
.
In Express.js 4, if you’re using async/await
and a promise is rejected (or an error is thrown), you had to manually pass the error to the next middleware using next(err)
// Express 4
app.get('/route', async (req, res, next) => {
try {
const result = await someAsyncFunction();
res.send(result);
} catch (err) {
next(err); // Manually pass the error to the error-handling middleware
}
});
This setup requires the try/catch
block in every route or middleware that uses async/await
to ensure that errors are properly caught and passed along to Express.js’ error handler.
Dropped Support for Older Node.js Versions
Express.js 5 officially adopts Node.js 18 as the minimum supported version. This means it’s time to upgrade your Node.js environment if you’re running older versions like Node.js 14.
Reintroduced app.router
The app.router
object, which was removed in Express.js 4, has returned in Express.js 5. However, it’s now just a reference to the base Express router. You no longer need to explicitly load it like in Express 3—it’s automatically available when you start using routing. This simplifies things compared to earlier versions like Express 3.
const express = require('express')
const app = express()
// Create a new router instance
const router = express.Router()
// Middleware that runs for any requests handled by this router
router.use((req, res, next) => {
console.log('Router middleware triggered')
next()
})
// Define a route that will handle requests to /events
router.get('/events', (req, res) => {
res.send('Event list')
})
// Use the router for requests to /calendar
app.use('/calendar', router)
app.listen(3000, () => {
console.log('Server is running on port 3000')
})
- The
router
object handles all requests that begin with/calendar
- If a request comes to
/calendar/events
, the router middleware runs and then the route handler responds with “Event list.” - The router can also handle multiple paths, helping you separate concerns across different parts of your app.
Stricter Error Handling for Invalid Status Codes
Express.js 5 will now throw an error if you try to use an invalid status code in your response. For example:
// This will throw an error in Express.js 5
res.status(999).send('Invalid status');
In Express.js 4, this would fail silently, but Express 5 enforces the correct use of valid HTTP status codes.
Improvements to res.render()
The res.render()
method now enforces asynchronous behavior across all view engines. This prevents bugs caused by older view engines that used synchronous rendering.
Body Parser Changes
Several updates have been made to the body parser:
- New option to customize the urlencoded body depth (default: 32)
- Removal of deprecated
bodyParser()
combination middleware req.body
is no longer always initialized to{}
- urlencoded parser now defaults
extended
tofalse
- Added support for Brotli lossless data compression
Project Revival and Governance
The Express team has recommitted to the project’s governance, adding more contributors to kickstart progress. The OpenJS Foundation Cross Project Council played a crucial role in putting together a plan to move Express forward, emphasizing the importance of robust project governance for large open-source projects.
Notable Enhancements in the Express.js Ecosystem
In addition to the core changes in Express.js, the project has seen several improvements across related packages:
-
Refactoring of dependencies: Express.js 5 now uses native Node.js methods like
Array.flat()
instead of relying on packages likearray-flatten
. Additionally, the project has dropped dependencies likepath-is-absolute
, favoring the built-inpath.isAbsolute()
method. -
Security improvements: A Threat Model has been added to improve security awareness and measures within the project. CodeQL (Static Application Security Testing) has also been integrated to catch vulnerabilities in the codebase.
-
CI Improvements: Continuous Integration (CI) pipelines have been optimized to cut down on duplicated runs and improve efficiency. Node.js 22 support has been added to the CI testing matrix, making Express.js compatible with the latest Node.js versions.
-
OSSF Scorecard: Express.js 5 now includes an OSSF Scorecard badge, which provides visibility into the project’s security health and open-source best practices.
-
Updated Dependencies: Core dependencies like
encodeurl
,send
,cookie-parser
, andqs
have all been updated to their latest versions to improve security, performance, and compatibility with modern Node.js.
References
- https://expressjs.com/2024/10/15/v5-release.html
- https://expressjs.com/en/5x/api.html
- https://expressjs.com/en/guide/migrating-5.html
- https://github.com/expressjs/express/releases/tag/v5.0.0