Async Middleware

Async Middleware and Automatic Promise Rejection

In Express 4 24,430 a rejected promise inside an async handler went nowhere: the framework called your function, ignored the promise it returned, and the request hung until the client gave up. That is why so much existing code wraps every handler in an asyncHandler helper or installs express-async-errors. Express 5 fixed it at the source. The router inspects the value a layer returns and, if it is a promise, attaches a rejection callback that calls next(error) for you, so async handlers reach your error middleware with no wrapper.

An async handler that rejects, with no wrapperJavaScript
app.get('/reject', async (req, res) => {
  const book = await Promise.reject(new Error('database unreachable'));
  res.json(book);
});
app.use((err, req, res, next) => res.status(503).json({ error: err.message }));
Output
GET /reject -> 503 {"error":"database unreachable"}

Delete the wrappers when you migrate, but know the boundary: Express only sees the promise your function returns. Anything escaping it is still an uncaught exception that can take the process down: