Updated Oct 11, 202615 min read

Express Alternatives in 2026

Modern TypeScript frameworks for teams moving beyond Express

Express was the default Node.js framework for over 15 years. It earned that position by being simple, flexible, and well-documented. But the backend landscape looks different in 2026. TypeScript is the norm, not the exception. Teams expect built-in validation, not a pile of middleware. And managing infrastructure alongside application code has become a real bottleneck as systems grow.

If you're building a new project or migrating an existing Express app, it's worth looking at what's available now. This guide covers five Express alternatives, each with a different philosophy about how much a framework should do for you.

For a broader comparison, see our Best TypeScript Backend Frameworks guide.

Express Alternatives: An Overview

FeatureEncore.tsFastifyNestJSHonoElysia
Primary Use CaseDistributed systemsSchema-validated APIsLarge team backendsEdge & serverlessBun-first APIs
Type SafetyNative TS typesJSON Schema + TypeBoxDecoratorsBuilt-inInferred from TypeBox schemas
Built-in ValidationYesYes(JSON Schema)Yes(decorators)Via middlewareYes(TypeBox)
Infrastructure from CodeYesNoNoNoNo
Built-in TracingYesNoNoNoNo
Auto API DocumentationYesYes(via plugins)Yes(via plugins)NoYes(via plugin)
Service DiscoveryYesNoNoNoNo
Learning CurveLowMediumHighLowLow
AI Agent CompatibilityBuilt-in infrastructure awarenessManual configuration neededManual configuration neededManual configuration neededManual configuration needed

Encore.ts

Encore

Encore.ts is designed for the problems that Express doesn't address: type-safe APIs, infrastructure management, service communication, and observability. Where Express gives you a blank canvas and lets you figure out validation, database connections, tracing, and deployment on your own, Encore provides these as built-in primitives.

The framework runs on a Rust-based runtime that handles HTTP parsing, validation, and I/O outside the Node.js event loop. In benchmarks, Encore.ts handles significantly more requests per second than Express. But performance isn't the main reason to switch. The real benefit is how much less code and configuration you need to get a production-quality backend running.

Requests/sec

Without validation
With schema validation
121,005
107,018
Encore
v1.38.7
101,611
33,772
Bun (+ Zod)
v1.1.12 / v3.23.8
82,617
35,124
Elysia (+ TypeBox)
v1.1.16 / v0.33.12
71,202
33,150
Hono (+ TypeBox)
v4.6.3 / v0.33.12
62,207
48,397
Fastify (+ Ajv)
v4.27.0 / v8.16.0
15,707
11,878
Express (+ Zod)
v4.19.2 / v3.23.8
Requests per second, with and without schema validation. See the benchmark code on GitHub.
import { api } from "encore.dev/api"; import { SQLDatabase } from "encore.dev/storage/sqldb"; const db = new SQLDatabase("users", { migrations: "./migrations" }); interface User { id: number; name: string; email: string; } export const getUser = api( { method: "GET", path: "/users/:id", expose: true }, async ({ id }: { id: number }): Promise<User> => { return await db.queryRow<User>`SELECT * FROM users WHERE id = ${id}`; } );

Compare this with Express, where you'd need to install and configure a validation library, set up a database connection pool, write error handling middleware, and add tracing instrumentation. In Encore, the TypeScript types handle validation, the database is provisioned automatically, and tracing works out of the box. The difference becomes more pronounced as your application grows. Each new Express endpoint requires manual validation setup, error handling, and middleware wiring. Each new Encore endpoint just needs a function signature with TypeScript types.

Key Features

  • Type-safe request validation using standard TypeScript types
  • Infrastructure primitives (databases, Pub/Sub, cron, caching) with automatic local provisioning
  • Type-safe service-to-service communication with generated clients
  • Built-in distributed tracing across services
  • Service catalog and auto-generated API documentation
  • Streaming APIs with WebSocket support
  • Rust-based runtime for high throughput

Benefits

For Express users, the biggest shift is going from "configure everything yourself" to "declare what you need." You write new SQLDatabase("users", { migrations: "./migrations" }) and a PostgreSQL database is provisioned automatically when you run your app locally. No Docker Compose files, no connection string management, no setup scripts.

Service-to-service communication is another area where Encore pulls ahead. In Express, calling another service means making HTTP requests with manually constructed URLs. In Encore, you import a function from another service and call it. The framework handles service discovery, serialization, and tracing automatically.

Built-in distributed tracing shows you how requests flow through your system without configuring OpenTelemetry, Jaeger, or any external tools. This is something Express teams typically spend significant time setting up and maintaining. Encore also generates a service catalog with auto-generated API documentation that stays in sync with your code, so you never have to maintain separate OpenAPI specs or Swagger files.

Encore distributed tracing showing request flow

Good to Know

Encore uses conventions for APIs and infrastructure that keep projects consistent as they grow. You can use standard npm packages alongside Encore's built-in primitives for anything the framework doesn't cover natively. The conventions mean every service follows the same patterns, which makes onboarding new team members straightforward.

When to Consider Encore.ts

Consider Encore when you're building production backends with multiple services, when you're tired of configuring databases and queues manually for local development, when you want type-safe APIs without adding validation libraries, or when you need observability without the overhead of setting up a tracing stack. It's also a strong fit if you want infrastructure-aware code that AI agents can generate and deploy with guardrails.

For a detailed head-to-head, see our Express.js vs Encore.ts comparison.

Try Encore.ts

Install the CLI and create a starter app:

Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

See the Encore.ts documentation for more details, follow the REST API tutorial to build a complete application, or check out Encore AI Integration for using Encore with AI coding agents.


Fastify

Fastify

Fastify was built as a direct response to Express's performance and architectural limitations. It uses JSON Schema for request and response validation, which provides both runtime checking and serialization optimization. The plugin architecture encourages clean separation of concerns, with each plugin managing its own dependencies and lifecycle.

For Express users, Fastify feels familiar enough that the migration is straightforward. Routes look similar, middleware translates to plugins, and the async/await support is first-class. The main adjustment is learning the JSON Schema validation layer and the plugin lifecycle. Many teams have migrated from Express to Fastify over the past few years, and the process is well documented with established patterns for converting middleware.

import Fastify from 'fastify'; const fastify = Fastify({ logger: true }); fastify.get('/users/:id', { schema: { params: { type: 'object', properties: { id: { type: 'string' } } }, response: { 200: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' }, email: { type: 'string' } } } } } }, async (request) => { return getUserById(request.params.id); }); fastify.listen({ port: 3000 });

Key Features

  • JSON Schema validation with automatic serialization optimization
  • Plugin-based architecture for modularity and encapsulation
  • First-class TypeScript support with type inference from schemas
  • Extensive logging via Pino integration
  • OpenAPI documentation generation from schemas

Benefits

Fastify gives you more structure than Express without being as opinionated as NestJS. The JSON Schema validation catches bad requests before they reach your handler code, and the same schemas can generate OpenAPI documentation. Performance is better than Express, and the plugin system provides a clean way to organize middleware and shared functionality.

Limitations

JSON Schema definitions are verbose. For complex request/response types, the schema can be longer than the handler code itself. You can use TypeBox to write schemas in TypeScript, but that's an additional layer. Like Express, Fastify doesn't manage infrastructure, observability, or service discovery. You're still responsible for configuring databases, setting up tracing, and managing deployment.

When to Consider Fastify

Consider Fastify when you want a structured upgrade from Express with JSON Schema validation, when you appreciate the plugin architecture for organizing code, or when you're building a single-service API and want better performance than Express offers.

For a deeper comparison, see our Fastify vs Encore.ts article.


NestJS

NestJS

NestJS takes the opposite approach from Express. Where Express is minimal and unopinionated, NestJS enforces a strict architecture inspired by Angular. Modules, controllers, providers, guards, interceptors, and pipes give you a comprehensive toolkit for building applications with consistent patterns across the codebase.

The dependency injection system is the core of NestJS's design. Every service is injectable, making unit testing straightforward and encouraging loose coupling. For teams coming from Express who struggled with inconsistent code organization as the project grew, NestJS provides the guardrails that Express deliberately avoids. The framework has a large community and extensive documentation, with solutions for GraphQL, WebSockets, microservices, task scheduling, and dozens of other use cases.

import { Controller, Get, Param } from '@nestjs/common'; import { UsersService } from './users.service'; @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @Get(':id') findOne(@Param('id') id: string) { return this.usersService.findOne(id); } }

Key Features

  • Angular-inspired module architecture with dependency injection
  • Comprehensive decorator-based validation via class-validator
  • First-class GraphQL and WebSocket support
  • Microservices patterns with multiple transport layers
  • Can use Express or Fastify as the underlying HTTP adapter

Benefits

NestJS scales well organizationally. When you have 10+ developers working on the same backend, the enforced architecture means everyone follows the same patterns. New team members can find their way around the codebase because modules, controllers, and services always look the same. The comprehensive feature set covers GraphQL, WebSockets, task scheduling, and more without reaching for external libraries.

Limitations

The learning curve is the steepest on this list. Even experienced Express developers need time to internalize modules, custom decorators, guards, interceptors, and the DI container. The decorator-heavy code can obscure what's happening at runtime, making debugging harder. For small teams or simple APIs, the overhead isn't worth it. And despite having microservices support, you still configure infrastructure, tracing, and deployment yourself.

When to Consider NestJS

Consider NestJS for large applications with many contributors with many developers, when consistent architecture matters more than simplicity, or when your team has Angular experience and wants familiar patterns on the backend.

For a detailed comparison, see our NestJS vs Encore.ts article.


Hono

Hono

Hono takes the minimalism that made Express popular and updates it for modern JavaScript runtimes. It runs on Cloudflare Workers, Deno, Bun, and Node.js with the same API. The framework is small, fast, and includes enough built-in middleware to handle common requirements without a sprawling dependency tree.

For Express users who liked the simplicity but want better TypeScript support and runtime flexibility, Hono is the most natural transition. The routing API feels familiar, middleware works similarly, and you can be productive within minutes. Hono has grown rapidly in adoption, particularly among teams deploying to Cloudflare Workers and other edge platforms where Express can't run at all.

import { Hono } from 'hono'; import { zValidator } from '@hono/zod-validator'; import { z } from 'zod'; const app = new Hono(); app.get( '/users/:id', zValidator('param', z.object({ id: z.string() })), async (c) => { const { id } = c.req.valid('param'); const user = await getUserById(id); return c.json(user); } ); export default app;

Key Features

  • Universal runtime support (Node.js, Deno, Bun, Cloudflare Workers)
  • Minimal bundle size for edge deployment
  • Built-in middleware for JWT, CORS, logging, and more
  • Validator middleware supporting Zod, Valibot, and TypeBox
  • Clean, modern API with first-class TypeScript support

Benefits

Hono is the Express of 2026 in terms of simplicity. The API is clean, the TypeScript support is native, and the runtime portability means you're not locked into Node.js. When deploying to Cloudflare Workers or similar edge platforms, Hono's tiny bundle size translates directly to faster cold starts and lower costs.

Limitations

Like Express, Hono is focused on HTTP routing and middleware. It doesn't manage infrastructure, provide service discovery, or include built-in observability. For traditional server-side backends with databases and message queues, you'll still need to configure everything yourself. The ecosystem is growing but still smaller than Express's.

When to Consider Hono

Consider Hono when deploying to edge platforms, when you want cross-runtime compatibility, or when building lightweight APIs where simplicity and bundle size matter more than infrastructure automation.

For a deeper comparison, see our Hono vs Encore.ts article.


Elysia

Elysia

Elysia is a TypeScript framework built for Bun. It keeps the small, route-first feel of Express, but adds schema validation and type inference directly into route definitions: you describe a request body with TypeBox, and Elysia validates it and types the handler from the same schema. Node.js compatibility exists, but Bun is the intended target.

Its other standout feature is Eden, a type-safe client that gives your frontend end-to-end types from the server's route definitions without code generation. If you're moving off Express and already using Bun, Elysia is the most direct way to get validation and typed clients without much ceremony.

import { Elysia, t } from 'elysia'; const app = new Elysia() .get('/users/:id', ({ params: { id } }) => getUser(id)) .post('/users', ({ body }) => createUser(body), { body: t.Object({ email: t.String({ format: 'email' }), name: t.String({ minLength: 1 }), }), }) .listen(3000);

Key Features

  • Built for Bun, with Node.js compatibility
  • Schema validation with TypeBox, with handler types inferred from the schema
  • Eden: end-to-end type-safe client for your frontend
  • Plugin system for cross-cutting concerns like auth and OpenAPI docs
  • Method-chaining API that stays close to Express's route-first style

Benefits

Elysia removes most of the glue code Express needs for validation and typing. Request bodies, params, and responses are validated and typed from one schema, so there's no separate validation middleware or hand-written interfaces to keep in sync. Eden carries those types to the frontend, which shortens the loop between backend changes and client code.

Limitations

Elysia is optimized for Bun, so teams standardized on Node.js get less out of it, and some Bun-specific APIs don't carry over. Its ecosystem is much smaller than Express's or Fastify's. Like the other HTTP frameworks here, it doesn't provide infrastructure management, distributed tracing, or type-safe service-to-service calls; Eden is designed for frontend-to-backend calls.

When to Consider Elysia

Consider Elysia when you're building on Bun, want validation and types inferred from one schema, or want end-to-end type safety with your frontend through Eden.


AI Code Generation

TypeScript's backend ecosystem has too many valid ways to structure things. AI coding agents pick a different combination of validation library, database access pattern, and project layout on every prompt. Express makes this worse because it has no structure at all - every AI prompt produces a completely different architecture with a different validation library, different ORM, different error handling pattern, and different project layout.

With Encore, the project's API patterns, infrastructure declarations, and service structure are already defined. An agent reads the existing conventions and follows them. There's one way to define an API, one way to declare a database, and one way to call another service.

Encore also provides an MCP server and editor rules (encore llm-rules init) that give agents access to database schemas, distributed traces, and service architecture. This means agents can generate queries that match your actual tables, debug with real request data, and verify their own work. Read more in How AI Agents Want to Write TypeScript.

How to Choose

The right Express alternative depends on what you're building and what frustrated you about Express. Start at the top and follow the first question you can answer with a yes:

Question 1

Do you want infrastructure provisioned from your code, without building a DevOps team internally?

Yes →
EncoreInfrastructure automation in your own AWS or GCP account
Question 2

Are you building several services that share databases, Pub/Sub, or cron jobs?

Yes →
EncoreType-safe service calls and built-in tracing
Question 3

Do you need high request throughput from a Node.js backend?

Yes →
EncoreRust-based runtime with 9x the throughput of Express.js
Question 4

Are you deploying to edge runtimes or serverless platforms like Cloudflare Workers?

Yes →
HonoSmall bundles that run on any runtime
Question 5

Is a large team relying on strict architectural conventions?

Yes →
NestJSModules, providers, and dependency injection
Question 6

Are you building on Bun and want end-to-end types with your frontend?

Yes →
ElysiaSchema-inferred types and the Eden client
FastifyJSON Schema validation and plugins, close to Express

In more detail:

Encore.ts addresses the most common complaints about Express: no built-in validation, no infrastructure management, no observability, and poor TypeScript integration. You get all of these from a single framework, plus significantly better performance. Encore's consistent conventions also mean AI coding agents can follow your project's patterns to generate production-ready code. For teams building production backends, especially with multiple services, Encore eliminates the most time-consuming parts of backend development that Express leaves to you.

Fastify is a good step up from Express if you want JSON Schema validation and a plugin architecture while keeping a similar mental model. It doesn't solve infrastructure or observability, but it adds structure where Express has none.

NestJS fits large teams that need strict architectural conventions. The learning curve is steep, but the consistency pays off when many developers work on the same codebase.

Hono is the right choice for edge computing and serverless. It's Express-like in philosophy but built for modern runtimes and minimal bundle sizes.

Elysia suits teams building on Bun that want validation and types inferred from one schema, plus end-to-end type safety with the frontend through Eden. It doesn't address infrastructure or observability.

For most teams moving away from Express, the underlying issue is that Express requires too much manual configuration for production backends. You end up spending more time on glue code, middleware configuration, and infrastructure setup than on application logic. Encore.ts addresses this more comprehensively than any other framework on this list, handling validation, infrastructure, observability, and service communication as built-in capabilities rather than external concerns. It also delivers significantly better performance through its Rust-based runtime, which handles the heavy lifting outside the Node.js event loop.


Evaluating your options? Join our Discord community to discuss framework choices with other TypeScript developers.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders