The Express.js team has released version 5.0.0, 10 years after the first major version release in 2014. The release focuses on stability and security with a view to enabling developers to write more robust Node.js applications.
Express 5 drops support for old versions of Node.js. The release note states:
This release drops support for Node.js versions before v18. This is an important change because supporting old Node.js versions has been holding back many critical performance and maintainability changes. This change also enables more stable and maintainable continuous integration (CI), adopting new language and runtime features, and dropping dependencies that are no longer required.
Following a security audit, the team decided to introduce changes in how path route matching works. To avoid regular expression Denial of Service (ReDoS) attacks, Express 5 no longer supports sub-expressions in regular expressions, for example /:foo(\d+)
.
app.get('/:id(\d+)', (req, res) => res.send(`ID: ${req.params.id}`));
Blake Embrey, member of the Express.JS technical committee provides an example of regular expression (e.g., /^/flights/([^/]+?)-([^/]+?)/?$/i
), that, when matched against '/flights/' + '-'.repeat(16_000) + '/x'
may take 300ms instead of running below one millisecond. The Express team recommends using a robust input validation library.
Express 5 also requires wildcards in regular expressions to be explicitly named or replaced with (.*)
** for clarity and predictability. Thus, paths like /foo*
must be updated to /foo(.*)
.
The syntax for optional parameters in routes also changes. Former Express 4’s :name?
becomes {/:name}
:
app.get('/user/:id?', (req, res) => res.send(req.params.id || 'No ID'));
app.get('/user{/:id}', (req, res) => res.send(req.params.id || 'No ID'));
Unnamed parameters in regex capture groups can no longer be accessed by index. Parameters must now be named:
app.get('/user(s?)', (req, res) => res.send(req.params[0]));
app.get('/user:plural?', (req, res) => res.send(req.params.plural));
Express 5 additionally enforces valid HTTP status codes, as a defensive measure against silent failures and arduous sessions of debugging responses.
res.status(978).send('Invalid status');
res.status(978).send('Invalid status');
Express.js 5 makes it easier to handle errors in async middleware and routes. Express 5 improves error handling in async. middleware and routes by automatically passing rejected promises to the error-handling middleware, removing the need for try/catch blocks.
app.get('/data', async (req, res, next) => {
try {
const result = await fetchData();
res.send(result);
} catch (err) {
next(err);
}
});
app.get('/data', async (req, res) => {
const result = await fetchData();
res.send(result);
});
While the Express team strives to keep the breaking changes minimal, the new release will require interested developers to migrate their Express code to the new version. Developers can review the migration guide available online.
Express.js is a project of the OpenJS Foundation (At-Large category). Developers are invited to read the full release note for additional technical details and examples.