Skip to content
All writing
BackendFeb 04, 20267 min read

Why I still pick Express over the new defaults

The unfashionable case for boring middleware. What Express buys you over Fastify, Hono, and Elysia once a project crosses a couple of years.

Every few months a new Node framework lands with a 2x-faster benchmark and a clever DX story. I read every one of them, build a small thing, and then keep starting new projects with Express. Here's why.

Performance is rarely the bottleneck

The shape of a typical web request — talk to a database, talk to a cache, render JSON — spends 95% of its time in IO, not framework overhead. Saving 30 microseconds in your router gains you nothing if your Postgres query takes 12 milliseconds.

The benchmarks aren't lying — Fastify and Hono really are faster on synthetic workloads. They just aren't faster on workloads that look like business software, which is most of them.

Boring composes well with time

Express's middleware contract is one function: (req, res, next). That's it. Every utility you'd want to write — auth, logging, rate limiting, request id, request validation — fits inside that signature without thinking. Every utility you'd want to import was written ten years ago and still works.

Newer frameworks have richer abstractions, which is great until you need to do something the abstraction doesn't anticipate. Then you're reading source, opening issues, and discovering that the maintainer is rewriting the routing internals next month.

When I do reach for something else

  • High-volume edge functions where the cold-start budget is small — Hono is genuinely better.
  • Greenfield projects on Bun where Elysia's type inference earns its keep.
  • When the team is all on a single framework and consistency matters more than my preference.

The hidden cost of novelty

Every dependency is a future migration. Express has been stable for so long that 'migrate off Express' is essentially never on a roadmap. That's a meaningful property when you're shipping something you intend to operate for five years.

Choose technology you can keep choosing for as long as you'll be paid to maintain the thing you're building.

The honest counterargument

Express's ecosystem isn't aging gracefully in every corner. Several core middleware packages are unmaintained, the types are inconsistent, and the async error handling story is still rougher than it needs to be. None of that is a dealbreaker for me, but I'm not going to pretend it doesn't exist.

Pick the boring tool until the cost of boring outweighs the cost of churn. For most of the work I do, that line is still a long way off.