Benchmarking Deno vs Node with GraphQL
Tags: deno, node, javascript, graphql
Published: 2022-12-20 17:33:49

Just over 1 month ago, [Deno has announced support for NPM](https://deno.com/blog/v1.28), which means that 1.3 million new modules can be used to build a Deno application. Also, it means that a lot of people can migrate from Node to Deno, just by changing some configurations and imports.

This got me thinking about moving my application, [Drakkle](https://play.google.com/store/apps/details?id=com.andresribeiro.drakkle), to Deno, but I couldn't find any benchmarks on GraphQL, so I decided to do some simple tests.

Instead of choosing the most popular stack (Apollo Server + Express), I decided to choose the most performant: Fastify + Mercurius.

## Coding

I love Typescript, but since it's a simple benchmark, Javascript seemed like a good enough choice.

Using the same example from the Mercurius documentation, an `add` query was created, which returns the sum of two numbers passed.

The code for Node looks like this:

```javascript
import Fastify from 'fastify'
import mercurius from 'mercurius'

const app = Fastify()

const schema = `
  type Query {
    add(x: Int, y: Int): Int
  }
`

const resolvers = {
  Query: {
    add: async (_, { x, y }) => x + y
  }
}

app.register(mercurius, {
  schema,
  resolvers
})

app.listen({ port: 3000, host: '0.0.0.0' })
```

The code for Deno was the same, except for the imports:

```javascript
import Fastify from 'npm:fastify'
import mercurius from 'npm:mercurius'
```

## Benchmarking

Using [autocannon](https://github.com/mcollina/autocannon), I did the following script to simulate 500 concurrent connections over 30 seconds:

```bash
npx autocannon -c 500 -d 30 -m POST --body 'query Add { add (x: 50, y: 50) }' -H 'Content-Type:application/graphql' localhost:3000/graphql
```

### Node

| Stat    | 2.5%  | 50%   | 97.5%  | 99%    | Avg      | Stdev    | Max    |
|---------|-------|-------|--------|--------|----------|----------|--------|
| Latency | 48 ms | 72 ms | 118 ms | 234 ms | 75.11 ms | 34.03 ms | 581 ms |

| Stat      | 1%     | 2.5%   | 50%    | 97.5%   | Avg     | Stdev   | Max    |
|-----------|--------|--------|--------|---------|---------|---------|--------|
| Req/Sec   | 1209   | 1209   | 6791   | 8231    | 6622.27 | 1391.98 | 1209   |
| Bytes/Sec | 231 kB | 231 kB | 1.3 MB | 1.57 MB | 1.26 MB | 266 kB  | 231 kB |

199k requests in 30.23s, 37.9 MB read

### Deno

| Stat    | 2.5%  | 50%   | 97.5%  | 99%    | Avg      | Stdev    | Max    |
|---------|-------|-------|--------|--------|----------|----------|--------|
| Latency | 114 ms | 155 ms | 240 ms | 420 ms | 162.46 ms | 56.72 ms | 1531 ms |

| Stat      | 1%     | 2.5%   | 50%    | 97.5%  | Avg    | Stdev  | Max    |
|-----------|--------|--------|--------|--------|--------|--------|--------|
| Req/Sec   | 988    | 988    | 3169   | 3565   | 3087.8 | 569.88 | 988    |
| Bytes/Sec | 180 kB | 180 kB | 577 kB | 649 kB | 562 kB | 104 kB | 180 kB |

93k requests in 30.36s, 16.9 MB read

## Conclusion

As you can see, **Node it's just over 2 times faster than the Deno**.

To try this further, I tried to compare by creating a fork of the process for each CPU, using Node's cluster module, but this module has not yet been ported to Deno.