五個框架的定位

Node.js 生態的 framework 分成兩個維度:大小(minimal vs batteries-included)和目標 runtime(Node.js only vs multi-runtime)。

Framework定位Runtime型別安全
Expressminimal,最成熟Node.jsTypeScript 可用,但不 native
Fastifyminimal but fast,schema-drivenNode.jsTypeScript 原生
Honoultra-minimal,跨 runtimeNode / Bun / CF Workers / DenoTypeScript 原生,RPC style
NestJSbatteries-included,Angular 架構Node.jsTypeScript 原生
ElysiaBun-first,端對端型別安全BunTypeScript 原生

Express:成熟、生態大、但設計老了

Express(2010)是 Node.js 後端的元老。優點是生態系最完整——幾乎任何功能都能找到 Express middleware;文件和 Stack Overflow 資源最多;幾乎所有 Node.js 後端工程師都看得懂。

// Express:宣告式、沒有魔法
const app = express();
app.use(express.json());
app.use(cors());
app.get('/users/:id', authenticate, async (req, res) => {
  const user = await userService.findById(req.params.id);
  res.json(user);
});

缺點

  • req.body 永遠是 any,TypeScript 只做表面工夫
  • 路由查找用 layer list,效能比 Fastify / Hono 差(小 API 感受不到,高 QPS 才有差)
  • 沒有 schema-based validation,要自己接 express-validator 或 zod
  • 沒有 typed route——handler signature 和 URL 沒有型別關聯

適合:熟悉 Express 生態的團隊、需要大量既有 middleware 的場景、prototype 快速開發。


Fastify:Express 的效能升級版

Fastify 解的是 Express 的兩個問題:效能型別安全

import Fastify from 'fastify';
 
const app = Fastify({ logger: true });
 
// Schema-driven:route schema 讓 body 有型別
app.post('/users', {
  schema: {
    body: {
      type: 'object',
      required: ['name', 'email'],
      properties: {
        name: { type: 'string' },
        email: { type: 'string', format: 'email' },
      },
    },
    response: {
      201: {
        type: 'object',
        properties: {
          id: { type: 'number' },
          name: { type: 'string' },
        },
      },
    },
  },
}, async (request, reply) => {
  // request.body 在這裡是 typed(透過 JSON Schema 推斷)
  const user = await userService.create(request.body);
  reply.status(201).send(user);
});

Fastify 用 JSON Schema 做 validation 和序列化,比 Express 的 JSON.stringify 快 2-3 倍(用 fast-json-stringify)。

缺點

  • Plugin 系統是 Fastify 的核心設計,不熟悉的人初期會被 encapsulation scope 搞混
  • JSON Schema 比 Pydantic / zod 更 verbose,型別推斷不如 zod 自然
  • 生態比 Express 小(但在快速追趕中)

適合:需要效能但不想用 NestJS 這麼重的架構;I/O 密集的高 QPS API。


Hono:超輕量、typed route、跨 runtime

Hono(2022)的設計目標是:輕量(比 Express 小 10 倍)、typed、跨 runtime(同一份程式碼可以跑在 Node.js / Bun / Cloudflare Workers / Deno)。

import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
 
const app = new Hono();
 
const createUserSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
});
 
app.post('/users',
  zValidator('json', createUserSchema),
  async (c) => {
    const data = c.req.valid('json'); // ← 完整型別,不是 any
    const user = await userService.create(data);
    return c.json(user, 201);
  }
);
 
// RPC style:client 可以用型別安全的方式呼叫
const route = app.get('/users/:id', (c) => {
  const id = c.req.param('id'); // ← typed
  return c.json({ id });
});
export type AppType = typeof route; // ← client 用這個推斷 API 型別

Hono 的 RPC style 讓 client(例如前端)可以用 hono/client import 後端的型別,不需要手寫 API type 或用 OpenAPI codegen。

缺點

  • 生態相對年輕(2022 年,比 Express 晚 12 年)
  • Cross-runtime 的能力讓它的 API 設計有些限制(要能在 CF Workers 跑就不能用 Node.js only 的 API)

適合:Edge function / serverless;需要跨 runtime 部署;想要 typed route 但不想用 NestJS。


NestJS:Angular 哲學 in Node.js

NestJS 的設計哲學直接借自 Angular:Module / Injectable / Controller / Guard / Pipe / Interceptor。

// 完整的 DI、lifecycle、module 系統
@Module({
  imports: [TypeOrmModule.forFeature([User])],
  providers: [UserService],
  controllers: [UserController],
})
export class UserModule {}
 
@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User) private userRepo: Repository<User>,
  ) {}
 
  async findById(id: number) {
    return this.userRepo.findOneByOrFail({ id });
  }
}
 
@Controller('users')
@UseGuards(AuthGuard)
export class UserController {
  constructor(private userService: UserService) {}
 
  @Get(':id')
  show(@Param('id', ParseIntPipe) id: number) {
    return this.userService.findById(id);
  }
}

NestJS 的 DI container 讓大型系統的依賴管理不失控;Module 系統讓功能拆分有明確邊界;Guard / Pipe / Interceptor 讓 middleware 邏輯有統一的插入點。

缺點

  • 學習曲線高(要先理解 Module / DI / Decorator 系統)
  • 效能比 Fastify / Hono 差(抽象層較多)
  • 小型 API 用 NestJS 是殺雞用牛刀

適合:大型企業後端;多人開發需要強制架構 convention;從 Angular 或 Spring 換過來的團隊。


Elysia:Bun-first,端對端型別安全

Elysia 是為 Bun runtime 設計的,充分利用 Bun 的效能優勢:

import { Elysia, t } from 'elysia';
 
const app = new Elysia()
  .post('/users', ({ body }) => {
    // body 是完整 typed,從 schema 推斷
    return userService.create(body);
  }, {
    body: t.Object({
      name: t.String({ minLength: 1 }),
      email: t.String({ format: 'email' }),
    }),
    response: t.Object({
      id: t.Number(),
      name: t.String(),
    }),
  });
 
// Eden Treaty:client 端型別安全 API 呼叫
const client = treaty<typeof app>('http://localhost:3000');
const { data } = await client.users.post({ name: 'Alice', email: 'alice@example.com' });
// data 是完整 typed,不需要手寫 API type

Elysia 的端對端型別安全比 Hono 的 RPC style 更完整。

缺點

  • 需要 Bun runtime(不能跑在 Node.js 上)
  • 生態最年輕,很多 middleware 要自己寫

適合:用 Bun 的專案;需要最高效能 + 最強型別安全的場景。


選擇框架的決策路徑

需要跨 runtime(CF Workers / Bun / Node)?
  → 是 → Hono

用 Bun 且在乎最高效能和端對端型別安全?
  → 是 → Elysia

大型系統、多人開發、需要強制架構 convention?
  → 是 → NestJS

需要效能但不要 NestJS 的複雜度?
  → 是 → Fastify

熟悉 Express 生態、不需要高效能、prototype 快速開發?
  → 是 → Express

沒有哪個是「最好的」——Express 在 2026 還在大量使用,不是因為沒有替代方案,而是因為它的 trade-off 在很多場景依然合理。


延伸閱讀