These benchmarks are based on the Fastify benchmarks repo. Our goal is to perform similarly to Fastify as we consider it the industry standard in terms of performance.
@mionkit/tun-typesThe test consists of an updateUser request with a complex User model (~1KB payload) that includes:
export interface User {
id: number;
username: string;
email: string;
profile: {
firstName: string;
lastName: string;
displayName: string;
bio?: string;
avatarUrl?: string;
dateOfBirth: Date;
};
role: "admin" | "user" | "guest" | "moderator";
status: "active" | "suspended" | "pending_verification" | "deactivated";
address: Address;
paymentMethods: PaymentMethod[]; // Discriminated union
preferences: UserPreferences;
createdAt: Date;
updatedAt: Date;
lastLoginAt?: Date;
tags: string[];
}
// ### mion ###
// the received user by the route is already validated and deserialized
// all Date fields are already JS Date objects (not strings from JSON.parse)
export const routes: Routes = {
updateUser: (ctx, user: User): User => {
user.updatedAt = new Date();
user.lastLoginAt = new Date();
user.profile.displayName = `${user.profile.firstName} ${user.profile.lastName.charAt(0)}.`;
return user;
},
};
// ### Other frameworks (Express, Fastify, Hono, etc.) ###
// Use Zod schemas for validation and date coercion
const UserSchema = z.object({
id: z.number(),
username: z.string(),
// ... full schema with nested objects, discriminated unions, etc.
createdAt: z.coerce.date(),
updatedAt: z.coerce.date(),
// ...
});
app.post("/updateUser", function (req, res) {
const user = UserSchema.parse(req.body); // Validates + deserializes dates
user.updatedAt = new Date();
user.lastLoginAt = new Date();
user.profile.displayName = `${user.profile.firstName} ${user.profile.lastName.charAt(0)}.`;
res.json(user);
});
In this benchmark the requests take considerably more time compared with the 'hello world' benchmark. This is mostly because each request is spending extra time on validation and serialization.
For this specific test, the performance of the libraries used for validation and serialization might be more important than the routing itself.
v24.13.0autocannon -c 100 -d 20.01 -p 10 localhost:3000 (two rounds; one to warm-up, one to measure)| Version | Router | Req (R/s) | Latency (ms) | Output (Mb/s) | Max Memory (Mb) | Max Cpu (%) | Validation | Description | |
|---|---|---|---|---|---|---|---|---|---|
| mion.bun | 0.6.2 | ✓ | 55899.2 | 17.38 | 57.67 | 77 | 102 | ✓ | mion using bun, automatic validation and serialization |
| hono.bun | 3.12.6 | ✓ | 52971.2 | 18.37 | 52.23 | 104 | 102 | ✓ | hono bun server with Zod validation |
| elysia.bun | 1.0.0 | ✓ | 43713.6 | 22.36 | 43.10 | 122 | 103 | ✓ | Elysia framework with TypeBox validation |
| mion | 0.6.2 | ✓ | 42712.0 | 22.89 | 45.98 | 170 | 111 | ✓ | Automatic validation and serialization out of the box |
| http-node | 16.18.0 | ✗ | 41384.0 | 23.65 | 43.26 | 163 | 110 | ✓ | bare node http server with Zod validation |
| fastify | 5.7.4 | ✓ | 31114.4 | 31.61 | 32.55 | 352 | 127 | ✓ | Fastify with native JSON Schema validation |
| express | 5.2.1 | ✓ | 30055.2 | 32.73 | 31.41 | 247 | 116 | ✓ | Express with Zod validation |
| hapi | 21.4.4 | ✓ | 28297.6 | 34.80 | 29.57 | 285 | 114 | ✓ | Hapi with Zod validation |
| hono | 3.12.6 | ✓ | 24819.2 | 39.68 | 25.58 | 691 | 126 | ✓ | hono node server with Zod validation |