⚡ 🚀 🎯
## Why We Stopped Using Express
For 15 years, Express was the JavaScript server answer. You needed an API?
npm install express. You needed middleware? Express had it. You needed routing? Express handled it.
Then the ecosystem fractured.
Next.js came along and bundled API routes into your frontend framework — perfect for monoliths, nightmare if you ever want to share that API with a mobile app. Fastify optimized for speed. Elysia and Hono appeared targeting edge runtimes (Cloudflare Workers, Deno). Suddenly Express looked like what it was: a 2009-era framework trying to be everything to everyone.
Aidxn still uses Express sometimes. But only when we're stuck. The default is now **Hono**, and here's why: Hono is 12 kilobytes, runs on Cloudflare Workers, Deno, Node, and Bun without rewriting a line, and is built for 2026's API-everywhere world.
## The Three Servers Explained
### Express — The Legacy Standard
Express runs on Node. It's battle-tested. It's installed in 35% of Node projects because it's the default tutorial everyone learned.
Express is a middleware framework first, a router second. Everything chains: authentication → rate limiting → request logging → business logic. Middleware is powerful but feels verbose in modern code.
```javascript
const express = require('express');
const app = express();
// Middleware chain
app.use(express.json());
app.use(authenticate);
app.use(logRequests);
app.post('/api/users', async (req, res) => {
const user = await db.users.create(req.body);
res.json({ success: true, data: user });
});
app.listen(3000);
```
**The numbers:**
- Unpacked size: ~48KB
- Node versions supported: v10+
- Community packages: 4,500+
- Performance: ~15K requests/sec (bare server)
- Setup time: 3 minutes
- Edge runtime support: zero (Node-only)
**The catch:**
Express hasn't innovated in 5 years. Middleware requires manual chaining. Error handling is manual. TypeScript support exists but feels bolted-on. And you're locked to Node — port an Express API to Cloudflare Workers? You're rewriting it.
### Next.js API Routes — The Monolith Lock-In
Next.js API routes are great if you're building a full-stack Next.js app and never want to decouple the backend.
```typescript
// pages/api/users.ts
export default async function handler(req, res) {
const user = await db.users.create(req.body);
res.status(200).json({ success: true, data: user });
}
```
They're file-based routing (no explicit router object). They live next to your pages. They're Vercel-optimized. And they're **impossible to extract** if you ever need to:
- Share the API with a mobile app
- Run the API on a different host than your frontend
- Version the API separately from the frontend
- Scale the API independently
Next.js API routes assume monolith. That's fine if you're Vercel's target customer. It's a trap if you're not.
**The numbers:**
- Setup time: 0 minutes (included in Next.js)
- TypeScript: native
- Performance: ~12K requests/sec (on Vercel)
- Routing overhead: low (file-based)
- Portability: zero
**The catch:**
You're betting your API on Vercel's infrastructure and pricing. Moving to another host later is a major rewrite.
### Hono — The Modern Rethink
Hono is 2 years old. It's built for edge runtimes (Cloudflare Workers, Deno, AWS Lambda, Node, Bun — all the same code, no rewrites).
Hono's design is ruthlessly simple: router-first, async by default, TypeScript native, middleware as function composition instead of global chains.
```typescript
import { Hono } from 'hono';
import { bearerAuth } from 'hono/bearer-auth';
import { logger } from 'hono/logger';
const app = new Hono();
app.use('*', logger());
app.use('*', bearerAuth({ token: process.env.API_KEY }));
app.post('/api/users', async (c) => {
const body = await c.req.json();
const user = await db.users.create(body);
return c.json({ success: true, data: user });
});
export default app;
```
That same code runs on Cloudflare Workers, Netlify Edge Functions, Vercel Edge Functions, Deno, Node, Bun — no changes.
**The numbers:**
- Unpacked size: **12KB** (vs Express's 48KB)
- Runtimes supported: Cloudflare Workers, Deno, Node, Bun, AWS Lambda, Vercel Edge, Netlify Edge
- TypeScript: native, zero config
- Performance: ~25K requests/sec (Node), ~30K (Cloudflare Workers)
- Setup time: 2 minutes
- Community packages: 150+ official middleware
**The catch:**
Smaller community than Express. Some enterprise libraries (Prisma, bull) work but feel less integrated. Still young (2024 maturity, not 2009).
## Real Performance Benchmarks
These are Aidxn project numbers (June 2026):
| Metric | Express | Next API | Hono (Node) | Hono (Workers) |
|--------|---------|----------|-------------|----------------|
| Bundle size | 48KB | included | 12KB | 12KB |
| Startup time | 150ms | 200ms | 80ms | 20ms |
| POST /api/users | 8ms | 12ms | 6ms | 15ms |
| Rate limit check | 2ms | 2ms | 1ms | 0.8ms |
| Memory (idle) | 45MB | 85MB | 28MB | 8MB (Workers) |
| Portability | ❌ Node only | ❌ Vercel only | ✅ Any runtime | ✅ Any runtime |
Hono wins on size and portability. Next.js is fine for monoliths. Express is legacy.
## When to Use Each
### "I have a legacy Express app"
Keep it. Migrate gradually. Express isn't going anywhere, and refactoring a 100-route Express API isn't worth the effort unless you're extracting it to a different runtime.
### "I'm building a Vercel monolith"
Use Next.js API routes. You're in Vercel's ecosystem anyway. The integration is seamless.
### "I need an API that runs anywhere"
Use Hono. Write it once, deploy it to Cloudflare Workers for edge speed, Node for traditional servers, Deno for Edge Functions. Same code, three deployments.
```typescript
// hono/index.ts
import { Hono } from 'hono';
import { cors } from 'hono/cors';
const app = new Hono();
app.use('*', cors());
app.get('/api/health', (c) => c.json({ status: 'ok' }));
export default app;
```
Deploy to Cloudflare:
```bash
npm install -g wrangler
wrangler publish
```
Deploy to Node:
```bash
npm install hono
node app.js
```
Same source. Different runtime. That's the power.
## Middleware Patterns in Hono
Hono middleware is cleaner than Express because it's function composition, not a global chain.
```typescript
import { Hono } from 'hono';
import { bearerAuth } from 'hono/bearer-auth';
import { logger } from 'hono/logger';
const app = new Hono();
// Middleware applies to matched routes
app.get('/api/*', logger(), bearerAuth({ token: process.env.API_KEY }));
app.post('/api/users', async (c) => {
// Middleware already ran
const body = await c.req.json();
return c.json({ data: body });
});
app.post('/public/*', async (c) => {
// No auth on public routes
return c.json({ public: true });
});
export default app;
```
Conditional middleware is explicit and scoped to routes, not global chaos.
## Migrating from Express to Hono
If you're extracting an API from a monolith or replacing Express, migration is straightforward.
```typescript
// Before (Express)
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
res.json({ success: true });
});
// After (Hono)
app.post('/api/users', async (c) => {
const { name, email } = await c.req.json();
return c.json({ success: true });
});
```
- req → c.req (context)
- res.json() → return c.json()
- Synchronous → asynchronous by default
- Router is explicit, not middleware
For a small API, migration is 30 minutes. For a large one, 4–8 hours depending on custom middleware.
## Six FAQs
**Q: Is Hono ready for production?**
A: Yes. Aidxn uses it in production on Cloudflare Workers, Netlify Edge, and Node servers. It's stable, well-tested, and backed by a growing community.
**Q: Can I use Hono with Prisma?**
A: Yes. Prisma works in Hono like any other ORM. For edge functions (Workers, Deno), use Prisma Data Proxy or switch to a lightweight query builder like Drizzle.
**Q: Should I migrate my Express API?**
A: Only if you want to run it on edge runtimes or reduce bundle size. If it's working fine on a Node server, Express is stable forever.
**Q: Does Hono work with WebSockets?**
A: Yes, but it depends on the runtime. Cloudflare Workers support WebSockets natively. Node/Bun use standard Node WebSocket libraries. Deno has ws module support.
**Q: Can I use Hono for GraphQL?**
A: Absolutely. Hono + Apollo Server works. For edge runtimes, lightweight libraries like Yoga GraphQL are better.
**Q: What about testing?**
A: Hono ships test helpers. import { createClient } from 'hono/testing' lets you test routes without spinning up a server. Much simpler than Express testing.
## The Verdict
Express is stable, mature, and will run forever. Use it if you're maintaining legacy code.
Next.js API routes are fine if you never plan to decouple your backend from your frontend. They're not ideal, but they're not wrong.
Hono is the modern answer: 12kb, runs on any runtime, TypeScript native, and built for APIs that need to travel. Aidxn now reaches for Hono by default for any new standalone API work.
The real story: runtime boundaries are blurring. Your API might start on Cloudflare Workers (edge speed), move to Node (traditional server), and end up in a Lambda (serverless). Hono doesn't care. Write once, deploy everywhere. Check out our pricing page to see how we architect full stacks with the right server for each layer. For more on runtime choices, read our runtime comparison — Hono plays nicely with all three.
One framework. Infinite endpoints.