mrkeyoor.com_
Sat 19 Sept 10:02 UTC
npmWeb Backendupdated 19 Sept 2026

express review

Express 5.2.1 is a Node web framework whose main abstraction is an ordered list of middleware and route handlers. It supplies routing, body parsers, response helpers, static file delivery, and hooks for template engines, while leaving databases, validation, authentication, and project layout to other modules. Express 5 sends rejected promises from async handlers to error middleware and requires newer path-to-regexp syntax for wildcards and optional segments. Our package check found CommonJS code that worked through require() and ESM import, but no bundled TypeScript declarations.

121.4Mdownloads / wk
Verdict

Express 5.2.1 installed in 1.3 seconds but left 65 packages and no bundled types in our sandbox, so its real advantage is middleware compatibility rather than a tiny dependency footprint. Pick it for conventional Node services; prefer Fastify or Hono when schemas or multi-runtime deployment define the project.

We installed it

Lab card: what happened when we installed expressScreenshot of express documentation
Install✓ · 1.3s65 packages on disk · 5 MB
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does express install cleanly?

Yes. In a fresh container with an empty cache, npm install express finished in 1 seconds, leaving 65 packages and 5 MB on disk. npm audit reported no known vulnerabilities.

Can express run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does express work with both ESM and CommonJS?

Yes. Both import 'express' and require('express') worked in Node 22 in our run. The package is published as CommonJS.

Does express include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

express or fastify: which should you use?

fastify: Use it for schema-led JSON APIs with integrated validation and serialization. Express 5.2.1 installed in 1.3 seconds but left 65 packages and no bundled types in our sandbox, so its real advantage is middleware compatibility rather than a tiny dependency footprint.

When should you not use express?

Schemas should control validation and serialization at every route; Fastify builds those operations into its route model

API stability4/5Express 5.2.1 still revolves around app, Router, middleware, req, and res, concepts carried forward from Express 4. The major release changes path matching, removes old conveniences, and automatically forwards rejected handler promises. Those changes have an official migration guide and keep the programming model recognizable, but route-heavy applications must test every wildcard, optional segment, and error path before upgrading.
Docs4/5Expressjs.com provides an API reference, installation and routing guides, middleware material, production security and performance advice, and a dedicated version 5 migration guide. The official pages document promise rejection and revised path syntax. Search results still surface many Express 4 examples, so developers must verify the version before copying routing or error-handling code from tutorials.
Maintenance4/5The unarchived GitHub repository was pushed on August 22, 2026, and reports 229 open issues and pull requests. npm lists 5.2.1, published December 1, 2025, and the project operates under OpenJS governance with a named technical committee and security process. Changes arrive conservatively, which supports long-lived applications but means feature proposals may wait behind compatibility and maintenance work.
Ecosystem5/5npm counted 131,895,868 Express downloads from August 19 through 25, 2026, while GitHub lists 69,394 stars. Authentication, sessions, uploads, tracing tools, template engines, and hosting platforms commonly document Express adapters. That breadth also includes abandoned third-party middleware, so each added package still needs its own ownership, release, dependency, and security check.

Discussed on

  1. hnExpressJS 5.044 points
  2. hnExpressJS 5.0 Released21 points
  3. hnExpress.js Releases Version 55 points
  4. hnExpressJS 5.0 Released4 points
  5. hnIssue for Express 5 re-opened by maintainer4 points

Use it if

  • An existing service already depends on Express routers or middleware such as Passport, multer, or express-session
  • A small Node API benefits from explicit middleware order and very few framework conventions
  • The team values an HTTP API that many Node developers already recognize
  • An Express 4 application needs a staged move to promise-aware Express 5 handlers
Skip it if

Setup reality

We installed Express 5.2.1 in a fresh Node 22 sandbox in 1.3 seconds. It left 65 packages and 5 MB on disk, and npm audit found 0 known vulnerabilities. Express declares 28 direct dependencies, 0 peer dependencies, and Node 18 or newer. Its own package is 104 KB unpacked under the MIT license. The CommonJS package has no exports map, though require() and ESM import both worked. We found no bundled TypeScript types.

Our esbuild browser attempt failed because the dependency graph uses Node server modules. Express belongs on the server. Middleware order is executable configuration: put express.json() before code that reads req.body, authentication before protected routers, the 404 handler after known routes, and four-argument error middleware last. A handler that neither sends a response nor calls next() leaves its request open. Parsing JSON also does not validate the resulting object.

Express 5 forwards a rejected route-handler promise to error middleware. Detached promises and work started after a response are outside that path. Preserve the err, req, res, next signature so Express recognizes the error handler, and delegate to the default handler when headers have already been sent. Route matching changed as well: wildcards need names, and braces replace several older optional patterns. Run route tests against the version 5 migration guide.

No credentials or framework config file are required, but production decisions remain. Set trust proxy only for the actual proxy chain before using req.ip or secure cookies. Choose body limits, CORS rules, request timeouts, rate controls, and validation deliberately. Save the http.Server returned by listen(), stop accepting traffic on SIGTERM, and close database or queue connections after in-flight work receives a bounded shutdown window.

Patterns

Start a server and keep its handle start-server

import express from 'express';
const app = express();
app.get('/', (req, res) => res.send('Hello'));
const server = app.listen(3000);

The returned http.Server is needed for a bounded shutdown; app.listen by itself does not close database pools.

Parse a limited JSON body parse-json

app.use(express.json({ limit: '1mb' }));
app.post('/items', (req, res) => {
  res.status(201).json({ name: req.body.name });
});

Register the parser before the route, then validate req.body because successful parsing proves only that the input was JSON.

Mount feature routes under one prefix mount-router

const router = express.Router();
router.get('/:id', (req, res) => res.json({ id: req.params.id }));
app.use('/users', router);

The router receives middleware that was registered before its mount point; later app middleware does not run first.

Continue an ordered middleware chain write-middleware

function requestId(req, res, next) {
  req.requestId = crypto.randomUUID();
  next();
}
app.use(requestId);

Call next once or finish the response. Doing neither leaves the connection pending.

Let Express 5 catch a rejected handler handle-async-error

app.get('/users/:id', async (req, res) => {
  const user = await db.findUser(req.params.id);
  res.json(user);
});

Express 5 forwards a rejected handler promise; detached background promises still need their own failure handling.

Install final error middleware handle-errors

app.use((err, req, res, next) => {
  if (res.headersSent) return next(err);
  res.status(err.status || 500).json({ error: 'request failed' });
});

All 4 parameters are required for Express to classify this function as error middleware.

Answer unmatched routes after routers return-404

app.use((req, res) => {
  res.status(404).json({ error: 'not found' });
});

Register this after every intended route and before the final error handler.

Stop accepting requests on SIGTERM shutdown-server

process.on('SIGTERM', () => {
  server.close(async () => {
    await db.close();
    process.exit(0);
  });
});

Add an application-specific deadline because server.close waits for existing connections and can otherwise delay termination.

Alternatives

PackageRegistryPick it when
fastifynpmUse it for schema-led JSON APIs with integrated validation and serialization
hononpmUse it for one router across Workers, Bun, Deno, and Node
koanpmUse it for a smaller async middleware kernel when the team will assemble the surrounding stack

More web backend guides

urllib3 · requests · ws · anyio · undici · httpx · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.