Update User Benchmarks

This is a more realistic scenario that involves validation and serialization of parameters.

What is tested?

The test consist of an updateUser request where the fields of the user must be deserialized and validated and response must be serialized.

The lastUpdate field is a date that must be transformed into a JS Date (deserialized) and validated, then a month is added to the Date and the updated user is send back in the response.

export interface User {
  id: number;
  name: string;
  surname: string;
  lastUpdate: Date;

// ### mion ###
// the received user by the route is already validated and deserialized
// user.lastUpdate is already a js date instead and string (result of JSON.parse)
const routes = {
  updateUser: (ctx, user: User): User => {
    user.lastUpdate.setMonth(user.lastUpdate.getMonth() + 1);
    return user;
} satisfies Routes;

// ### Express ###
// A plugin must be used to parse the json body
// validation must be done manually and user.lastUpdate must be deserialized manually into a date
// in this case developer would have to manually write `isUser` and `deserializeUser` functions. (check src code fo those functions)
app.post('/updateUser', function (req, res) {
  const rawUser = req.body?.updateUser;
  if (!isUser(rawUser)) throw 'app error, invalid parameter, not a user';
  const user = deserializeUser(rawUser);
  user.lastUpdate.setMonth(user.lastUpdate.getMonth() + 1);


  • Machine: darwin x64 | 8 vCPUs | 16.0GB Mem
  • Node: v18.17.0
  • Run: Sat Oct 07 2023 14:14:11 GMT+0100 (Irish Standard Time)
  • Method: autocannon -c 100 -d 40.02 -p 10 localhost:3000 (two rounds; one to warm-up, one to measure)

Req (R/s)


Throughput (Mb/s)


Latency (ms)


Max Memory (Mb)


Memory Series (MB)


Notes on current results:

We are aware that the memory consumption is a bit higher than other frameworks, this is in part because there is types cache storing all extra run type metadata of the code, and partly due to some design decision to not reuse the native request and response objects within mion routes.

This said it is just the baseline memory which is a bit Higher (when the code gets loaded) and mion memory keeps steady under heavy workloads. Please note both mion and @deepkit/type are still in beta an there is room for improvement.

Throughput is usually bigger on mion as we send/receive slightly more data in the request/response body compared to other frameworks.

View in Benchmark's Repo

Results Table

FrameworkVersionRouterReq (R/s)Latency (ms)Output (Mb/s)Max Memory (Mb)Max Cpu (%)ValidationDescription
http-node16.18.0โœ—17071.858.044.1085120โœ—bare node http server, should be the theoretical upper limit in node.js performance
mion.bun0.6.2โœ“17005.958.273.94110107โœ“mion using bun, automatic validation and serialization
fastify4.10.2โœ“15164.065.413.6698118-Validation using schemas and ajv. schemas are generated manually or using third party tools
mion0.6.2โœ“13971.871.023.86100117โœ“Automatic validation and serialization out of the box
restify11.1.0โœ“11498.286.392.95133118โœ—manual validation or third party tools
hapi21.3.2โœ“8177.9121.651.97105132โœ—validation using joi or third party tools
deepkit1.0.1-alpha.75โœ“5268.5188.921.27283142โœ“Automatic validation and serialization out of the box
express4.18.2โœ“4471.4222.631.07119126โœ—manual validation or third party tools