# API Maker Documentation : Benchmarks > The pages of https://docs.apimaker.dev in the order of the navigation, each with its title, its description and its URL. The code is in TypeScript : the Markdown of a page (its URL with .md) has every language. --- # API Maker benchmarks : requests per second and memory on real servers > API Maker benchmarks on 7 Linode servers, 1 to 8 vCPUs, shared and dedicated : requests per second, latency and memory on MongoDB, PostgreSQL and MySQL. Source: https://docs.apimaker.dev/v4/docs/benchmarks/index.html Benchmarks · API Maker 4.0.0 · 7 servers · measured 12 October 2026 **How fast is API Maker ? Measured, not promised.** API Maker installed by its own installer on 7 Linode servers, from 1 to 8 vCPUs, shared and dedicated CPU, its databases on the same machine. Every API loaded for 15 seconds by autocannon from a second server, two rounds each, on MongoDB, PostgreSQL and MySQL : 136,821,729 requests, 0 errors. Every page shows the full autocannon output and what each part of the server held in memory. Get all · 8 vCPU dedicated 12,640req/s a whole table, MongoDB · 1 vCPU : 2,435 Get by id, cached · 8 vCPU 47,980req/s answered from Redis · 1 vCPU : 12,140 Custom API · 8 vCPU 8,893req/s TypeScript, get all inside, run in the server · in the sandbox 7,569 API Maker memory 84MB the process at rest · up to 112 MB on 8 vCPUs ## The servers ### Shared CPU - [1 vCPU · 1 GB RAM · Shared CPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html) : Linode Nanode 1 GB (g6-nanode-1), $5 a month. Get all 2,435 req/s, get by id cached 12,140 req/s, custom API 1,909 req/s (MongoDB). (12 October 2026 · 8,390,598 requests, 0 errors) - [2 vCPU · 4 GB RAM · Shared CPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html) : Linode 4 GB (g6-standard-2), $24 a month. Get all 4,692 req/s, get by id cached 18,970 req/s, custom API 3,178 req/s (MongoDB). (12 October 2026 · 13,338,901 requests, 0 errors) - [4 vCPU · 8 GB RAM · Shared CPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html) : Linode 8 GB (g6-standard-4), $48 a month. Get all 7,423 req/s, get by id cached 26,444 req/s, custom API 5,178 req/s (MongoDB). (12 October 2026 · 19,370,117 requests, 0 errors) - [8 vCPU · 32 GB RAM · Shared CPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html) : Linode 32 GB (g6-standard-8), $192 a month. Get all 11,002 req/s, get by id cached 44,564 req/s, custom API 8,062 req/s (MongoDB). (12 October 2026 · 30,678,581 requests, 0 errors) ### Dedicated CPU - [2 vCPU · 4 GB RAM · Dedicated CPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html) : Linode Dedicated 4 GB (g6-dedicated-2), $36 a month. Get all 3,712 req/s, get by id cached 16,455 req/s, custom API 2,591 req/s (MongoDB). (12 October 2026 · 10,989,400 requests, 0 errors) - [4 vCPU · 8 GB RAM · Dedicated CPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html) : Linode Dedicated 8 GB (g6-dedicated-4), $72 a month. Get all 7,614 req/s, get by id cached 32,588 req/s, custom API 5,228 req/s (MongoDB). (12 October 2026 · 21,624,231 requests, 0 errors) - [8 vCPU · 16 GB RAM · Dedicated CPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html) : Linode Dedicated 16 GB (g6-dedicated-8), $144 a month. Get all 12,640 req/s, get by id cached 47,980 req/s, custom API 8,893 req/s (MongoDB). (12 October 2026 · 32,429,901 requests, 0 errors) ## Results at a glance **Get all, public : requests per second** · MongoDB · PostgreSQL · MySQL [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html) · shared · $5 / month · 2,435 · 3,787 · 4,623 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html) · shared · $24 / month · 4,692 · 5,577 · 6,660 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html) · shared · $48 / month · 7,423 · 8,395 · 9,375 [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html) · shared · $192 / month · 11,002 · 13,054 · 13,816 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html) · dedicated · $36 / month · 3,712 · 4,782 · 5,418 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html) · dedicated · $72 / month · 7,614 · 8,912 · 10,000 [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html) · dedicated · $144 / month · 12,640 · 12,641 · 13,748 A whole table of ten rows, read from the database on every request. **Get by id with caching, public : requests per second** · MongoDB · PostgreSQL · MySQL [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html) · shared · $5 / month · 12,140 · 12,083 · 12,193 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html) · shared · $24 / month · 18,970 · 19,622 · 19,858 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html) · shared · $48 / month · 26,444 · 26,617 · 27,185 [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html) · shared · $192 / month · 44,564 · 43,050 · 43,160 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html) · dedicated · $36 / month · 16,455 · 16,517 · 16,379 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html) · dedicated · $72 / month · 32,588 · 33,015 · 32,897 [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html) · dedicated · $144 / month · 47,980 · 47,888 · 48,818 One row, answered from Redis. | Server | CPU · price / month | Get all, MongoDB | Get all, PostgreSQL | Get all, MySQL | Get by id, cached | Custom API | API Maker at rest | |---|---|--:|--:|--:|--:|--:|--:| | [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html) | Shared · $5 | **2,435** | **3,787** | **4,623** | 12,140 | 1,909 | 84 MB | | [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html) | Shared · $24 | **4,692** | **5,577** | **6,660** | 18,970 | 3,178 | 101 MB | | [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html) | Shared · $48 | **7,423** | **8,395** | **9,375** | 26,444 | 5,178 | 109 MB | | [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html) | Shared · $192 | **11,002** | **13,054** | **13,816** | 44,564 | 8,062 | 112 MB | | [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html) | Dedicated · $36 | **3,712** | **4,782** | **5,418** | 16,455 | 2,591 | 99 MB | | [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html) | Dedicated · $72 | **7,614** | **8,912** | **10,000** | 32,588 | 5,228 | 104 MB | | [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html) | Dedicated · $144 | **12,640** | **12,641** | **13,748** | 47,980 | 8,893 | 111 MB | Requests per second : the average of two rounds of 15 seconds with 100 connections, public APIs ; get by id cached and the custom API on MongoDB. **[All results](https://docs.apimaker.dev/v4/docs/benchmarks/summary.html)** puts every API of every server side by side, with the latencies and the memory. The page of each server gives every API public and with both tokens, on the three databases, with the full autocannon output and the memory and CPU of every part. ## WebSockets API Maker serves WebSockets on the port of its APIs. The same servers were filled with WebSocket clients, each with both tokens and a subscription : 26,484 clients connected at once on 1 vCPU and 1 GB, 3,662,564 on 8 vCPUs and 32 GB, 8.5 to 8.8 KB per client. - [WebSocket benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/index.html) : How many connections one server holds, the memory when it is full, new clients and notifications a second. - [Scale to N users](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html) : One big server or several small ones, the picture of N users, and the rule to count the servers. - [All WebSocket results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html) : Every server side by side : clients, memory per client, delivery times. ## What is measured Every API is measured on MongoDB, PostgreSQL and MySQL, public and with both tokens (`x-am-authorization` + `x-am-user-authorization`, checked on every request) : - **Get all** : The schema API of a table answers all its rows. - **Get all with caching** : The same request on a table whose API settings say `enableCaching: true`. - **Get all by stream** : `GET …//stream`. - **Custom API calling get all** : A custom API written in TypeScript, `return await g.sys.db.getAll({ instance, database, collection })`. - **Custom API in the sandbox** : The same custom API, with one line more. - **Get all with a pre hook** : Get all, with both tokens, on a table whose get all API has a pre hook written in TypeScript. - **Get by id** : One row by its primary key. - **Get by id with caching** : One row by its primary key, on a table with `enableCaching: true`. - **Insert one row** : `POST …/
/save-single-or-multiple` with one row of 9 columns in the body. - **Custom API without a database** : what running code costs, in the server (lean code) and in the sandbox. - **More connections** : from 10 to 1,000 clients at once. The data is the [API Maker benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`) : ten rows of customers, ten columns each, in every table. ## How it is measured 1. **A real installation** API Maker is installed by its [installer](https://docs.apimaker.dev/v4/docs/getting-started/install-on-server.html) with its default answers, MongoDB and Redis in Docker on the same server, PostgreSQL and MySQL from their official images. 2. **Only what is needed runs** While a database is measured, the other ones are stopped. API Maker is restarted, its two sandboxes started and the swap emptied before each database. 3. **A second server makes the load** autocannon runs on a dedicated server of the same data centre, on the private network, sized to the server under test and sampled too : it never comes near its limit. 4. **Every answer is checked** Before its load, the answer of each API is checked (status, ten rows, the row), and the APIs with tokens are checked to refuse a request without them. Errors, non-2xx answers and timeouts are counted : 0 in 136,821,729 requests. 5. **Two rounds, the average** 5 seconds of warm-up, then 15 seconds measured, two times, the second time in the reverse order. The page shows the average and the autocannon output of the round closer to it. 6. **Memory and CPU every second** The server samples its CPU (with steal time), its memory, the API Maker process and every container while the load runs. The whole method, with the settings of every API and the commands to run it yourself : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html). ## Questions ### How many requests per second can API Maker serve ? On the servers measured, with MongoDB, Redis and the database under test on the same machine, a whole table of ten rows (get all, public, MongoDB) was answered 2,435 times a second on 1 shared vCPU, 4,692 times a second on 2 shared vCPUs, 7,423 times a second on 4 shared vCPUs, 11,002 times a second on 8 shared vCPUs, 3,712 times a second on 2 dedicated vCPUs, 7,614 times a second on 4 dedicated vCPUs, 12,640 times a second on 8 dedicated vCPUs. A cached row reached 47,980 requests per second on 8 dedicated vCPUs. ### Is API Maker fast on a small server ? On the smallest Linode server (1 vCPU, 1 GB, $5 a month), API Maker answered 2,435 requests per second for a whole table on MongoDB (PostgreSQL 3,787, MySQL 4,623) and 12,140 for a cached row. ### How much memory does API Maker need ? The API Maker process held 84 to 112 MB at rest on these servers, with its two sandboxes running beside it. Most of the memory of a server goes to the databases and to the sandboxes which run your code : each server page shows every part, at rest and under load. ### Why is the database on the same server ? It is the cheapest way to run API Maker, and the hardest test : API Maker, its sandboxes and the database share the same vCPUs, so every number counts the work of all of them. ### How are the benchmarks made ? API Maker is installed by its own installer on a fresh server, the load comes from autocannon on a second server of the same data centre, every API runs two rounds of 15 seconds and the average is shown with the full autocannon output of a round. --- # API Maker benchmark results : every API on every server > Every API Maker benchmark side by side : req/s and latency on 7 Linode servers (1 to 8 vCPUs, shared and dedicated), scaling, memory. Source: https://docs.apimaker.dev/v4/docs/benchmarks/summary.html Benchmarks · All results · 7 servers **Every API, every server : side by side.** The average requests per second of every API Maker benchmark, on 7 Linode servers from 1 to 8 vCPUs, shared and dedicated CPU, on MongoDB, PostgreSQL and MySQL. 136,821,729 requests, 0 errors. Each number links to its run, with the full autocannon output. Servers 7 4 shared CPU · 3 dedicated CPU APIs per server 46 15 on each of 3 databases + a custom API without one Requests 137million 2 rounds of 15 s per API, plus the sweeps of connections Errors 0 non-2xx, errors, timeouts ## Every API on every server **MongoDB** Requests per second (the average of two rounds of 15 seconds, 100 connections) : | API | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | Get all | [**2,435**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all) | [**4,692**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all) | [**7,423**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all) | [**11,002**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all) | [**3,712**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all) | [**7,614**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all) | [**12,640**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all) | | Get all · both tokens | [**2,439**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all) | [**4,425**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all) | [**7,021**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all) | [**11,882**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all) | [**3,564**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all) | [**7,220**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all) | [**12,106**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all) | | Get all with caching | [**11,054**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-caching) | [**18,195**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-caching) | [**26,115**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-caching) | [**41,093**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-caching) | [**15,152**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-caching) | [**29,762**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-caching) | [**43,980**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-caching) | | Get all with caching · both tokens | [**8,709**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-caching) | [**14,144**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-caching) | [**20,550**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-caching) | [**34,364**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-caching) | [**11,750**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-caching) | [**23,619**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-caching) | [**36,123**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-caching) | | Get all by stream | [**2,545**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-by-stream) | [**4,548**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-by-stream) | [**6,724**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-by-stream) | [**10,646**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-by-stream) | [**3,661**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-by-stream) | [**7,342**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-by-stream) | [**11,898**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-by-stream) | | Get all by stream · both tokens | [**2,548**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-by-stream) | [**4,297**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-by-stream) | [**6,737**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-by-stream) | [**11,025**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-by-stream) | [**3,462**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-by-stream) | [**6,933**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-by-stream) | [**11,516**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-by-stream) | | Custom API calling get all QuickJS | [**1,909**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-calling-get-all) | [**3,178**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-calling-get-all) | [**5,178**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-calling-get-all) | [**8,062**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-calling-get-all) | [**2,591**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-calling-get-all) | [**5,228**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-calling-get-all) | [**8,893**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-calling-get-all) | | Custom API calling get all · both tokens QuickJS | [**1,699**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-calling-get-all) | [**2,957**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-calling-get-all) | [**4,910**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-calling-get-all) | [**8,393**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-calling-get-all) | [**2,420**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-calling-get-all) | [**4,933**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-calling-get-all) | [**8,426**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-calling-get-all) | | Custom API in the sandbox Sandbox | [**1,389**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-in-the-sandbox) | [**3,015**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-in-the-sandbox) | [**4,649**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-in-the-sandbox) | [**7,636**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-in-the-sandbox) | [**2,269**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-in-the-sandbox) | [**4,491**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-in-the-sandbox) | [**7,569**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-in-the-sandbox) | | Get all with a pre hook · both tokens QuickJS | [**1,984**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-a-pre-hook) | [**3,339**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-a-pre-hook) | [**5,327**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-a-pre-hook) | [**8,512**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-a-pre-hook) | [**2,713**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-a-pre-hook) | [**5,460**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-a-pre-hook) | [**9,279**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-a-pre-hook) | | Get by id | [**3,100**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id) | [**5,397**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id) | [**8,076**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id) | [**12,297**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id) | [**4,323**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id) | [**8,777**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id) | [**14,224**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id) | | Get by id · both tokens | [**3,044**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id) | [**4,947**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id) | [**7,513**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id) | [**12,654**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id) | [**4,044**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id) | [**8,182**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id) | [**13,443**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id) | | Get by id with caching | [**12,140**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id-with-caching) | [**18,970**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id-with-caching) | [**26,444**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id-with-caching) | [**44,564**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id-with-caching) | [**16,455**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id-with-caching) | [**32,588**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id-with-caching) | [**47,980**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id-with-caching) | | Get by id with caching · both tokens | [**9,481**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id-with-caching) | [**14,695**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id-with-caching) | [**20,887**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id-with-caching) | [**36,219**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id-with-caching) | [**12,553**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id-with-caching) | [**25,516**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id-with-caching) | [**38,521**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id-with-caching) | | Insert one row | [**1,156**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#insert-one-row) | [**2,352**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#insert-one-row) | [**3,198**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#insert-one-row) | [**4,620**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#insert-one-row) | [**1,735**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#insert-one-row) | [**3,574**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#insert-one-row) | [**5,490**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#insert-one-row) | Latency in milliseconds, p50 / **p99**, of the same runs : | API | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | Get all | 39 / **46** | 20 / **40** | 11 / **28** | 8 / **20** | 26 / **68** | 12 / **28** | 7 / **17** | | Get all · both tokens | 39 / **52** | 22 / **38** | 14 / **28** | 7 / **17** | 27 / **48** | 13 / **27** | 7 / **17** | | Get all with caching | 9 / **13** | 5 / **8** | 3 / **5** | 2 / **3** | 6 / **10** | 3 / **5** | 2 / **3** | | Get all with caching · both tokens | 11 / **17** | 7 / **10** | 4 / **7** | 2 / **4** | 8 / **12** | 4 / **6** | 2 / **4** | | Get all by stream | 38 / **46** | 21 / **39** | 14 / **33** | 8 / **21** | 26 / **50** | 13 / **27** | 8 / **17** | | Get all by stream · both tokens | 39 / **54** | 23 / **39** | 14 / **29** | 8 / **18** | 29 / **48** | 13 / **26** | 8 / **18** | | Custom API calling get all QuickJS | 53 / **69** | 31 / **50** | 19 / **34** | 12 / **23** | 38 / **62** | 18 / **32** | 11 / **20** | | Custom API calling get all · both tokens QuickJS | 61 / **125** | 33 / **54** | 19 / **34** | 11 / **21** | 41 / **67** | 20 / **35** | 11 / **21** | | Custom API in the sandbox Sandbox | 75 / **97** | 31 / **64** | 20 / **42** | 12 / **28** | 42 / **77** | 21 / **41** | 13 / **24** | | Get all with a pre hook · both tokens QuickJS | 52 / **66** | 29 / **50** | 18 / **34** | 11 / **24** | 36 / **61** | 18 / **31** | 10 / **20** | | Get by id | 31 / **37** | 18 / **33** | 11 / **26** | 7 / **18** | 22 / **42** | 11 / **22** | 6 / **14** | | Get by id · both tokens | 33 / **44** | 20 / **35** | 12 / **23** | 7 / **15** | 24 / **41** | 12 / **22** | 7 / **14** | | Get by id with caching | 7 / **12** | 5 / **8** | 3 / **5** | 2 / **3** | 6 / **9** | 3 / **4** | 2 / **3** | | Get by id with caching · both tokens | 10 / **16** | 6 / **10** | 4 / **7** | 2 / **4** | 8 / **12** | 3 / **6** | 2 / **4** | | Insert one row | 83 / **110** | 38 / **83** | 30 / **63** | 21 / **38** | 58 / **99** | 27 / **52** | 17 / **32** | **PostgreSQL** Requests per second (the average of two rounds of 15 seconds, 100 connections) : | API | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | Get all | [**3,787**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all) | [**5,577**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all) | [**8,395**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all) | [**13,054**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all) | [**4,782**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all) | [**8,912**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all) | [**12,641**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all) | | Get all · both tokens | [**3,560**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all) | [**5,290**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all) | [**7,680**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all) | [**12,013**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all) | [**4,384**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all) | [**8,245**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all) | [**11,913**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all) | | Get all with caching | [**11,064**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-caching) | [**17,836**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-caching) | [**26,420**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-caching) | [**39,947**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-caching) | [**14,883**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-caching) | [**30,205**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-caching) | [**43,173**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-caching) | | Get all with caching · both tokens | [**8,797**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-caching) | [**14,083**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-caching) | [**20,113**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-caching) | [**32,966**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-caching) | [**11,615**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-caching) | [**24,179**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-caching) | [**35,403**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-caching) | | Get all by stream | [**3,989**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-by-stream) | [**5,866**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-by-stream) | [**8,226**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-by-stream) | [**12,914**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-by-stream) | [**4,837**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-by-stream) | [**9,098**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-by-stream) | [**13,073**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-by-stream) | | Get all by stream · both tokens | [**3,461**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-by-stream) | [**5,189**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-by-stream) | [**7,486**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-by-stream) | [**12,049**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-by-stream) | [**4,427**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-by-stream) | [**8,490**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-by-stream) | [**12,162**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-by-stream) | | Custom API calling get all QuickJS | [**2,178**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-calling-get-all) | [**3,806**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-calling-get-all) | [**5,658**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-calling-get-all) | [**9,350**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-calling-get-all) | [**3,059**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-calling-get-all) | [**5,886**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-calling-get-all) | [**9,176**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-calling-get-all) | | Custom API calling get all · both tokens QuickJS | [**2,016**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-calling-get-all) | [**3,461**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-calling-get-all) | [**5,158**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-calling-get-all) | [**8,433**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-calling-get-all) | [**2,801**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-calling-get-all) | [**5,442**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-calling-get-all) | [**8,561**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-calling-get-all) | | Custom API in the sandbox Sandbox | [**1,871**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-in-the-sandbox) | [**3,423**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-in-the-sandbox) | [**5,126**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-in-the-sandbox) | [**8,682**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-in-the-sandbox) | [**2,389**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-in-the-sandbox) | [**4,673**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-in-the-sandbox) | [**7,916**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-in-the-sandbox) | | Get all with a pre hook · both tokens QuickJS | [**2,318**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-a-pre-hook) | [**3,884**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-a-pre-hook) | [**6,151**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-a-pre-hook) | [**9,668**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-a-pre-hook) | [**3,246**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-a-pre-hook) | [**6,280**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-a-pre-hook) | [**9,524**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-a-pre-hook) | | Get by id | [**4,105**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id) | [**6,325**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id) | [**9,446**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id) | [**13,656**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id) | [**5,090**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id) | [**9,655**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id) | [**13,571**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id) | | Get by id · both tokens | [**3,887**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id) | [**5,739**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id) | [**8,233**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id) | [**12,548**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id) | [**4,626**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id) | [**8,790**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id) | [**12,656**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id) | | Get by id with caching | [**12,083**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id-with-caching) | [**19,622**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id-with-caching) | [**26,617**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id-with-caching) | [**43,050**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id-with-caching) | [**16,517**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id-with-caching) | [**33,015**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id-with-caching) | [**47,888**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id-with-caching) | | Get by id with caching · both tokens | [**9,402**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id-with-caching) | [**14,989**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id-with-caching) | [**21,238**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id-with-caching) | [**34,322**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id-with-caching) | [**12,500**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id-with-caching) | [**25,875**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id-with-caching) | [**38,045**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id-with-caching) | | Insert one row | [**1,818**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#insert-one-row) | [**3,021**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#insert-one-row) | [**3,969**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#insert-one-row) | [**5,754**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#insert-one-row) | [**2,335**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#insert-one-row) | [**4,236**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#insert-one-row) | [**5,874**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#insert-one-row) | Latency in milliseconds, p50 / **p99**, of the same runs : | API | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | Get all | 25 / **51** | 18 / **22** | 11 / **14** | 7 / **9** | 20 / **24** | 11 / **13** | 7 / **10** | | Get all · both tokens | 28 / **36** | 18 / **22** | 12 / **15** | 8 / **10** | 22 / **27** | 12 / **14** | 8 / **10** | | Get all with caching | 8 / **13** | 5 / **8** | 3 / **5** | 2 / **3** | 6 / **10** | 3 / **5** | 2 / **3** | | Get all with caching · both tokens | 11 / **17** | 7 / **12** | 4 / **8** | 3 / **4** | 8 / **12** | 4 / **6** | 2 / **4** | | Get all by stream | 24 / **31** | 17 / **20** | 12 / **14** | 7 / **9** | 20 / **25** | 10 / **13** | 7 / **9** | | Get all by stream · both tokens | 29 / **37** | 19 / **23** | 13 / **15** | 8 / **10** | 22 / **26** | 11 / **13** | 8 / **10** | | Custom API calling get all QuickJS | 46 / **57** | 26 / **30** | 17 / **20** | 10 / **13** | 32 / **37** | 16 / **19** | 10 / **13** | | Custom API calling get all · both tokens QuickJS | 48 / **57** | 28 / **32** | 19 / **22** | 11 / **14** | 35 / **41** | 18 / **21** | 11 / **14** | | Custom API in the sandbox Sandbox | 52 / **100** | 28 / **51** | 19 / **35** | 11 / **20** | 40 / **72** | 21 / **38** | 12 / **22** | | Get all with a pre hook · both tokens QuickJS | 42 / **53** | 25 / **31** | 16 / **18** | 10 / **12** | 30 / **36** | 15 / **18** | 10 / **13** | | Get by id | 24 / **31** | 15 / **19** | 10 / **12** | 7 / **8** | 19 / **22** | 10 / **12** | 7 / **9** | | Get by id · both tokens | 25 / **32** | 17 / **21** | 11 / **17** | 7 / **10** | 20 / **40** | 11 / **13** | 7 / **11** | | Get by id with caching | 8 / **12** | 5 / **7** | 3 / **5** | 2 / **3** | 5 / **9** | 3 / **4** | 2 / **3** | | Get by id with caching · both tokens | 10 / **16** | 6 / **10** | 4 / **7** | 2 / **4** | 7 / **12** | 3 / **5** | 2 / **4** | | Insert one row | 54 / **64** | 33 / **38** | 24 / **28** | 17 / **19** | 42 / **49** | 23 / **28** | 16 / **19** | **MySQL** Requests per second (the average of two rounds of 15 seconds, 100 connections) : | API | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | Get all | [**4,623**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all) | [**6,660**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all) | [**9,375**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all) | [**13,816**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all) | [**5,418**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all) | [**10,000**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all) | [**13,748**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all) | | Get all · both tokens | [**4,126**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all) | [**5,902**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all) | [**8,338**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all) | [**12,645**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all) | [**4,939**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all) | [**9,236**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all) | [**12,712**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all) | | Get all with caching | [**11,245**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-caching) | [**18,227**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-caching) | [**25,630**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-caching) | [**40,335**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-caching) | [**15,123**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-caching) | [**30,217**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-caching) | [**44,027**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-caching) | | Get all with caching · both tokens | [**8,870**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-caching) | [**13,394**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-caching) | [**20,763**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-caching) | [**33,000**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-caching) | [**11,626**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-caching) | [**24,025**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-caching) | [**35,915**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-caching) | | Get all by stream | [**4,213**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-by-stream) | [**5,815**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-by-stream) | [**8,355**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-by-stream) | [**12,489**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-by-stream) | [**5,034**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-by-stream) | [**9,458**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-by-stream) | [**13,095**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-by-stream) | | Get all by stream · both tokens | [**3,662**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-by-stream) | [**5,317**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-by-stream) | [**7,469**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-by-stream) | [**11,587**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-by-stream) | [**4,518**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-by-stream) | [**8,733**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-by-stream) | [**12,340**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-by-stream) | | Custom API calling get all QuickJS | [**2,419**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-calling-get-all) | [**4,090**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-calling-get-all) | [**6,016**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-calling-get-all) | [**9,698**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-calling-get-all) | [**3,357**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-calling-get-all) | [**6,513**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-calling-get-all) | [**9,820**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-calling-get-all) | | Custom API calling get all · both tokens QuickJS | [**2,231**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-calling-get-all) | [**3,666**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-calling-get-all) | [**5,536**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-calling-get-all) | [**8,962**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-calling-get-all) | [**3,058**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-calling-get-all) | [**6,032**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-calling-get-all) | [**9,129**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-calling-get-all) | | Custom API in the sandbox Sandbox | [**2,170**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-in-the-sandbox) | [**3,834**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-in-the-sandbox) | [**5,486**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-in-the-sandbox) | [**9,181**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-in-the-sandbox) | [**2,714**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-in-the-sandbox) | [**5,174**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-in-the-sandbox) | [**8,657**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-in-the-sandbox) | | Get all with a pre hook · both tokens QuickJS | [**2,688**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-a-pre-hook) | [**4,389**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-a-pre-hook) | [**6,768**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-a-pre-hook) | [**10,192**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-a-pre-hook) | [**3,524**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-a-pre-hook) | [**6,820**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-a-pre-hook) | [**10,204**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-a-pre-hook) | | Get by id | [**5,090**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id) | [**7,155**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id) | [**9,893**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id) | [**14,402**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id) | [**5,874**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id) | [**10,654**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id) | [**14,510**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id) | | Get by id · both tokens | [**4,526**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id) | [**6,551**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id) | [**8,892**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id) | [**13,222**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id) | [**5,304**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id) | [**9,758**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id) | [**13,517**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id) | | Get by id with caching | [**12,193**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id-with-caching) | [**19,858**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id-with-caching) | [**27,185**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id-with-caching) | [**43,160**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id-with-caching) | [**16,379**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id-with-caching) | [**32,897**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id-with-caching) | [**48,818**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id-with-caching) | | Get by id with caching · both tokens | [**9,217**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id-with-caching) | [**15,385**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id-with-caching) | [**22,684**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id-with-caching) | [**34,667**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id-with-caching) | [**12,515**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id-with-caching) | [**25,837**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id-with-caching) | [**38,544**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id-with-caching) | | Insert one row | [**1,651**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#insert-one-row) | [**2,371**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#insert-one-row) | [**3,181**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#insert-one-row) | [**3,532**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#insert-one-row) | [**2,081**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#insert-one-row) | [**3,462**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#insert-one-row) | [**3,542**](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#insert-one-row) | Latency in milliseconds, p50 / **p99**, of the same runs : | API | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | Get all | 21 / **27** | 14 / **17** | 10 / **12** | 6 / **8** | 18 / **22** | 9 / **11** | 7 / **9** | | Get all · both tokens | 23 / **31** | 16 / **20** | 12 / **17** | 7 / **10** | 20 / **24** | 10 / **12** | 7 / **10** | | Get all with caching | 8 / **13** | 5 / **8** | 3 / **6** | 2 / **3** | 6 / **9** | 3 / **5** | 2 / **3** | | Get all with caching · both tokens | 11 / **17** | 7 / **10** | 4 / **7** | 3 / **4** | 8 / **13** | 4 / **6** | 2 / **4** | | Get all by stream | 22 / **29** | 17 / **21** | 12 / **14** | 8 / **10** | 19 / **23** | 10 / **12** | 7 / **9** | | Get all by stream · both tokens | 26 / **34** | 18 / **22** | 13 / **15** | 8 / **10** | 21 / **26** | 11 / **13** | 8 / **10** | | Custom API calling get all QuickJS | 41 / **51** | 24 / **28** | 16 / **19** | 10 / **12** | 30 / **35** | 15 / **17** | 10 / **12** | | Custom API calling get all · both tokens QuickJS | 44 / **53** | 27 / **31** | 17 / **20** | 11 / **14** | 32 / **38** | 16 / **19** | 10 / **13** | | Custom API in the sandbox Sandbox | 43 / **70** | 25 / **46** | 17 / **33** | 10 / **19** | 35 / **64** | 19 / **35** | 11 / **20** | | Get all with a pre hook · both tokens QuickJS | 37 / **47** | 22 / **27** | 14 / **17** | 9 / **13** | 27 / **59** | 14 / **17** | 9 / **13** | | Get by id | 19 / **25** | 13 / **16** | 9 / **11** | 6 / **8** | 16 / **20** | 9 / **11** | 6 / **8** | | Get by id · both tokens | 21 / **28** | 15 / **19** | 10 / **13** | 7 / **9** | 18 / **22** | 10 / **12** | 7 / **9** | | Get by id with caching | 8 / **12** | 4 / **7** | 3 / **5** | 2 / **3** | 5 / **9** | 2 / **4** | 2 / **3** | | Get by id with caching · both tokens | 10 / **16** | 6 / **9** | 4 / **6** | 2 / **4** | 7 / **12** | 3 / **5** | 2 / **4** | | Insert one row | 59 / **71** | 41 / **49** | 31 / **35** | 28 / **35** | 48 / **54** | 29 / **33** | 28 / **38** | The custom API without a database, requests per second : in the server (lean code) 1 vCPU shared **8,096** · 2 vCPU shared **14,731** · 4 vCPU shared **26,046** · 8 vCPU shared **47,967** · 2 vCPU dedicated **10,790** · 4 vCPU dedicated **21,532** · 8 vCPU dedicated **39,192** ; in the sandbox 1 vCPU shared **9,258** · 2 vCPU shared **12,669** · 4 vCPU shared **17,702** · 8 vCPU shared **27,302** · 2 vCPU dedicated **9,953** · 4 vCPU dedicated **18,562** · 8 vCPU dedicated **27,920**. ## More vCPUs API Maker is one process which uses every vCPU of its server : the same APIs, from the smallest server to the largest. **Get all, public, MongoDB : by vCPUs** · Shared CPU · Dedicated CPU 1 vCPUshared 1 GB $5 · 2,435 2 vCPUsshared 4 GB $24 · dedicated 4 GB $36 · 4,692 · 3,712 4 vCPUsshared 8 GB $48 · dedicated 8 GB $72 · 7,423 · 7,614 8 vCPUsshared 32 GB $192 · dedicated 16 GB $144 · 11,002 · 12,640 **Get by id with caching, public, MongoDB : by vCPUs** · Shared CPU · Dedicated CPU 1 vCPUshared 1 GB $5 · 12,140 2 vCPUsshared 4 GB $24 · dedicated 4 GB $36 · 18,970 · 16,455 4 vCPUsshared 8 GB $48 · dedicated 8 GB $72 · 26,444 · 32,588 8 vCPUsshared 32 GB $192 · dedicated 16 GB $144 · 44,564 · 47,980 **Custom API calling get all, public, MongoDB : by vCPUs QuickJS** · Shared CPU · Dedicated CPU 1 vCPUshared 1 GB $5 · 1,909 2 vCPUsshared 4 GB $24 · dedicated 4 GB $36 · 3,178 · 2,591 4 vCPUsshared 8 GB $48 · dedicated 8 GB $72 · 5,178 · 5,228 8 vCPUsshared 32 GB $192 · dedicated 16 GB $144 · 8,062 · 8,893 | API · database | 1 vCPU
shared | 2 vCPU
shared | 4 vCPU
shared | 8 vCPU
shared | 2 vCPU
dedicated | 4 vCPU
dedicated | 8 vCPU
dedicated | |---|--:|--:|--:|--:|--:|--:|--:| | Get all · MongoDB | 2,435 | 4,692 × 1.9 | 7,423 × 3.0 | 11,002 × 4.5 | 3,712 × 1.5 | 7,614 × 3.1 | 12,640 × 5.2 | | Get all · PostgreSQL | 3,787 | 5,577 × 1.5 | 8,395 × 2.2 | 13,054 × 3.4 | 4,782 × 1.3 | 8,912 × 2.4 | 12,641 × 3.3 | | Get all · MySQL | 4,623 | 6,660 × 1.4 | 9,375 × 2.0 | 13,816 × 3.0 | 5,418 × 1.2 | 10,000 × 2.2 | 13,748 × 3.0 | | Get by id with caching · MongoDB | 12,140 | 18,970 × 1.6 | 26,444 × 2.2 | 44,564 × 3.7 | 16,455 × 1.4 | 32,588 × 2.7 | 47,980 × 4.0 | | Get by id with caching · PostgreSQL | 12,083 | 19,622 × 1.6 | 26,617 × 2.2 | 43,050 × 3.6 | 16,517 × 1.4 | 33,015 × 2.7 | 47,888 × 4.0 | | Get by id with caching · MySQL | 12,193 | 19,858 × 1.6 | 27,185 × 2.2 | 43,160 × 3.5 | 16,379 × 1.3 | 32,897 × 2.7 | 48,818 × 4.0 | | Custom API calling get all · MongoDB QuickJS | 1,909 | 3,178 × 1.7 | 5,178 × 2.7 | 8,062 × 4.2 | 2,591 × 1.4 | 5,228 × 2.7 | 8,893 × 4.7 | | Custom API in the sandbox · MongoDB Sandbox | 1,389 | 3,015 × 2.2 | 4,649 × 3.3 | 7,636 × 5.5 | 2,269 × 1.6 | 4,491 × 3.2 | 7,569 × 5.5 | | Get all with a pre hook · MongoDB QuickJS | 1,984 | 3,339 × 1.7 | 5,327 × 2.7 | 8,512 × 4.3 | 2,713 × 1.4 | 5,460 × 2.8 | 9,279 × 4.7 | *× n* : the requests per second against the 1 vCPU server (1 GB of memory : it also used its swap). From 1 to 8 shared vCPUs : get all ×4.5 on MongoDB, ×3.4 on PostgreSQL and ×3.0 on MySQL, get by id with caching ×3.7, the custom API ×4.2. On every server the database, Redis and the sandboxes run beside API Maker and take their share of the same vCPUs. ## Memory The API Maker process at rest (with its two sandboxes started, before any request) and the most it held under load, the two sandboxes at rest, and the whole server : at rest with MongoDB, and the most it used while any database was loaded. | Server | CPU | API Maker at rest | API Maker under load | Sandboxes at rest | Server at rest | Server under load | |---|---|--:|--:|--:|--:|--:| | [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#memory) | shared | 84 MB | 111 MB | 50 MB | 686 MB | 807 MB of 961 MB | | [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#memory) | shared | 101 MB | 125 MB | 50 MB | 803 MB | 1658 MB of 3,915 MB | | [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#memory) | shared | 109 MB | 142 MB | 55 MB | 872 MB | 2048 MB of 7,941 MB | | [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#memory) | shared | 112 MB | 154 MB | 55 MB | 1102 MB | 2710 MB of 32,095 MB | | [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#memory) | dedicated | 99 MB | 127 MB | 50 MB | 773 MB | 1600 MB of 3,915 MB | | [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#memory) | dedicated | 104 MB | 140 MB | 55 MB | 872 MB | 2024 MB of 7,941 MB | | [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#memory) | dedicated | 111 MB | 176 MB | 55 MB | 946 MB | 2602 MB of 15,991 MB | ## WebSockets API Maker serves WebSockets on the port of its APIs. The same servers were filled with WebSocket clients, each with both tokens and a subscription : 26,484 clients connected at once on 1 vCPU and 1 GB, 3,662,564 on 8 vCPUs and 32 GB, 8.5 to 8.8 KB per client. - [WebSocket benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/index.html) : How many connections one server holds, the memory when it is full, new clients and notifications a second. - [Scale to N users](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html) : One big server or several small ones, the picture of N users, and the rule to count the servers. - [All WebSocket results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html) : Every server side by side : clients, memory per client, delivery times. ## Questions ### Does API Maker scale with more vCPUs ? Yes : API Maker is one process which uses every vCPU of its server. Get all on MongoDB went from 2,435 requests per second on 1 vCPU to 4,692 on 2 shared, 7,423 on 4 shared, 11,002 on 8 shared, 3,712 on 2 dedicated, 7,614 on 4 dedicated, 12,640 on 8 dedicated. The database runs on the same server, so its own work grows with the load too. --- # How API Maker is benchmarked > How API Maker is benchmarked - Linode servers of 1 to 8 vCPUs, autocannon with 100 connections for 15 s, two rounds, the dataset, every API setting and the commands to run it yourself. Source: https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html The benchmarks measure what you would get yourself : API Maker set up by its own installer on a plain cloud server, the databases on the same machine, and the load sent from a second server. This page shows every step, so you can check any number, or run the benchmarks again. | | | |---|---| | Servers | 7 [Linode](https://www.linode.com) servers in Mumbai, from 1 to 8 vCPUs, shared and dedicated CPU, all on the same CPU (AMD EPYC 7642). Each one runs API Maker and its databases. | | Load | autocannon 8 on a second, dedicated server in the same data centre : 100 connections, 5 seconds of warm-up, then 15 seconds measured. | | Rounds | Every API runs twice, the second time in reverse order. The pages show the average of the two. | | Data | The [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) : 10 customers with 10 columns each, in MongoDB, PostgreSQL and MySQL. | | Installation | The API Maker installer with its default answers and no reverse proxy. One setting changed : the sandboxes keep running. | | Checks | Every API answers once before its load : the status and the rows are checked, and an API with tokens refuses a request with none, or only one. Every error, non-2xx answer and timeout is counted. | ## The servers Every benchmark uses two servers in the same data centre : | | Server under test | Load generator | |---|---|---| | Runs | API Maker, its MongoDB and Redis, PostgreSQL, MySQL, the sandboxes | autocannon, nothing else | | Plan | Shared or dedicated CPU, as named on each page | Dedicated CPU, four times the vCPUs of the server under test | | System | Ubuntu 24.04 LTS | Ubuntu 24.04 LTS, Node.js 24.21.0, autocannon 8.0.0 | | Network | Private network of the data centre | The same network, 0.5 ms away (ping) | The load comes from its own machine, so autocannon never takes CPU away from API Maker. That machine has dedicated CPUs, so its speed does not depend on its neighbours, and it is big enough never to be the limit : it was never more than 29 % busy during a run (42 % for the 1 vCPU server). Every page shows how busy it was. | Server under test | Load generator | autocannon threads | |---|---|--:| | 1 vCPU | Dedicated 8 GB (g6-dedicated-4) : 4 vCPUs | 4 (25 connections each) | | 2 vCPU, shared and dedicated | Dedicated 16 GB (g6-dedicated-8) : 8 vCPUs | 5 (20 connections each) | | 4 vCPU, shared and dedicated | Dedicated 32 GB (g6-dedicated-16) : 16 vCPUs | 10 (10 connections each) | | 8 vCPU, shared and dedicated | Dedicated 64 GB (g6-dedicated-32) : 32 vCPUs | 20 (5 connections each) | ### Enough autocannon threads One autocannon thread cannot keep up with the fastest APIs. On the 1 vCPU server, *get by id with caching* gave about 10,400 requests per second with one thread, and about 12,000 with four, at the same latency. So autocannon runs several threads, which share the 100 connections. To be sure the threads were not the limit, the same API was loaded again after each run, with more threads. It gave the same requests per second : | Server | Threads of the run : req/s | More threads : req/s | |---|--:|--:| | [2 vCPU, shared](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html) | 5 : 19,709 and 19,524 | 10 : 19,766 and 20,058 | | [2 vCPU, dedicated](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html) | 5 : 16,442 and 16,466 | 10 : 16,176 and 16,412 | | [4 vCPU, shared](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html) | 10 : 26,932 and 27,201 | 20 : 27,304 and 26,271 | | [4 vCPU, dedicated](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html) | 10 : 32,748 and 32,841 | 20 : 32,998 and 32,970 | | [8 vCPU, shared](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html) | 20 : 41,740 and 41,994 | 25 : 42,075 and 42,190 | | [8 vCPU, dedicated](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html) | 20 : 48,650 and 48,364 | 25 : 47,617 and 47,700 | ### The same CPU, at the same time A Linode server runs on whatever CPU its host has. All seven servers under test run on the **AMD EPYC 7642**, so every size and both plans are compared on the same CPU. The load generators run on AMD EPYC 7642 or 7713 ; each page names its own. All seven servers were measured at the same time, each with its own load generator. Linode placement groups (strict *anti-affinity*) kept the three shared CPU servers of 2, 4 and 8 vCPUs on three different hosts, and the three dedicated servers too. Every page shows the steal time of each run : the CPU the hypervisor gave to other servers. ### Why 100 connections The fastest server (8 dedicated vCPUs) was loaded with 100, 200 and 400 connections, 20 seconds each : | API | 100 connections | 200 | 400 | Server busy | |---|--:|--:|--:|--:| | Get by id with caching, public, MongoDB | 45,742 | 46,061 | 44,016 | 87 to 90 % | | Get all, public, MongoDB | 11,059 | 11,114 | 11,049 | 95 % | | Custom API with both tokens, PostgreSQL | 5,395 | 5,962 | 6,128 | 99 to 100 % | At 100 connections the server already works at full speed. More connections mostly add waiting : the latency doubles at each step, for few more requests. The *more connections* runs of every page, from 10 to 1,000, say the same for *get all* : above 100 connections it gained 2.0 % at most. Only *get by id with caching* on the smallest server gained more : on 1 shared vCPU, 250 connections gave 15,248 requests per second against 12,096 with 100, at twice the latency (16 ms p50 against 8 ms). ## The installation API Maker is installed on a fresh server with its own [installer](https://docs.apimaker.dev/v4/docs/getting-started/install-on-server.html), its default answers and no reverse proxy, so nothing stands between autocannon and API Maker : ```sh bash install.sh --default --primary --caddy=no --ssl=no --qa_uat_prod=no --package=api-maker-4.0.0-linux-x64.tar.gz ``` The installer sets up Docker, MongoDB 8.0.10 and Redis 7.0.5 in Docker, swap, and API Maker as a systemd service. API Maker keeps its default settings : - one worker thread per vCPU ; - the Redis of the installation for cached answers, kept two hours (`redisValueExpireInSeconds` 7200) ; - two sandboxes per environment of an account (`sandboxCountForAdmin`), each opening up to one runner per vCPU while it is busy ; - no request logs : a fresh installation has no database for them. One setting is changed, in `~/config/.env` : ```sh am__sandbox__removeSandboxInactiveSinceMinutes=1440 ``` By default, a sandbox nobody used for 5 minutes stops, and the next custom API starts it again. Here the two sandboxes of the account keep running while a database is measured, so every API runs with them, and their memory is counted. ### PostgreSQL and MySQL PostgreSQL 18 and MySQL 8.4 run from their official images. On the servers of 2 to 8 vCPUs they allow 500 connections (100 and 151 by default) ; the 1 vCPU server keeps their defaults : ```sh docker run -d --name bench_postgres -e POSTGRES_PASSWORD=… -p 5432:5432 postgres:18 -c max_connections=500 docker run -d --name bench_mysql -e MYSQL_ROOT_PASSWORD=… -p 3306:3306 mysql:8.4 --max-connections=500 ``` Code that runs in a sandbox opens connection pools of its own, one per runner. On 8 vCPUs, a custom API in the sandbox on PostgreSQL can hold **161 connections** : 2 sandboxes × 8 runners × a pool of 10, plus the pool of API Maker itself. That is more than the 100 PostgreSQL allows by default. If your server has many vCPUs and runs code on a SQL database, raise `max_connections`, or lower *Max pool connections* of the instance. The MongoDB data of the benchmarks lives in the MongoDB of API Maker itself (database `am_bench`), the way a small installation keeps everything in one MongoDB. ## The data Every table holds the ten rows of the benchmark dataset. One row : ```json { "_id": "60ae2488c37cd955cc144161", "customer_id": 2, "first_name": "NICK", "last_name": "WAHLBERG", "phone": 1123456789, "last_update": "2006-02-15T04:34:00.330Z", "pincode": 111111, "shipping_id": 2, "dob": "2022-10-30T03:25:03.000Z", "country": "India" } ``` Each database (`am_bench` in MongoDB, PostgreSQL and MySQL) has six tables. API Maker made the schema of each from the table : | Table | Its APIs | Caching | |---|---|---| | `customers_public` | Public | Off | | `customers` | Both tokens | Off | | `customers_public_cached` | Public | On | | `customers_cached` | Both tokens | On | | `customers_pre_hook` | Both tokens, a pre hook on its get all | Off | | `inserts_public` | Public : the insert benchmark writes here | Off | In SQL, `customer_id` is the primary key (`SERIAL` / `AUTO_INCREMENT` in `inserts_public`) and the dates are `TIMESTAMP(3)` / `DATETIME(3)`. In PostgreSQL the URLs name the tables with their schema : `public.customers_public`. ## The APIs The settings of the APIs of a table (`__COLLECTION_SETTINGS__`), for each kind of table : **Public** ```typescript import * as T from 'types'; let settings: T.IInstanceApiSettingsTypes = { enableCaching: false, apiAccessType: T.EAPIAccessType.IS_PUBLIC, }; module.exports = settings; ``` **Both tokens** ```typescript import * as T from 'types'; let settings: T.IInstanceApiSettingsTypes = { enableCaching: false, apiAccessType: T.EAPIAccessType.TOKEN_ACCESS, authProviders: ["bench_token_mongodb"], }; module.exports = settings; ``` **Cached** ```typescript import * as T from 'types'; let settings: T.IInstanceApiSettingsTypes = { enableCaching: true, apiAccessType: T.EAPIAccessType.IS_PUBLIC, }; module.exports = settings; ``` The custom APIs are TypeScript : ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` The custom API with both tokens is the same, with `apiAccessType: TOKEN_ACCESS` and the token generator of its database in `authProviders`, and reads `customers`. The custom API without a database returns `{ message: 'Hello from API Maker', time: 1 }`. ### In the server or in the sandbox The code above is **lean** : it only reads what it is given and calls `g.sys`. API Maker runs lean code inside the server, with QuickJS, on the thread that answers the request : the request never leaves the server. The pre hook below is lean too. Code that needs more (a package, `g.shared`, the clock, a timer, `try`) runs in a sandbox of the account : a container with Node.js 24. To measure both, every database also has a custom API that runs in the sandbox : the same code with one more line, which reads `Date.now()` and so is not lean. The custom API without a database has a sandbox twin too (`{ message: 'Hello from the sandbox', time: Date.now() }`). **The custom API which runs in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const started = Date.now(); // the time of the machine : this code runs in the sandbox of the account return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` ### The pre hook The table `customers_pre_hook` has the settings of *both tokens*, and a pre hook on its get all API (`SCHEMA_GET_ALL`) : row scoping, the pre hook most applications write. It reads the signed-in person from `x-am-user-authorization` and keeps the rows of their country : **Pre hook of SCHEMA_GET_ALL on customers_pre_hook** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { if (!g.req.isApiRequestFromUser) return; const person = g.req.auth.authAMDB; // the person, from x-am-user-authorization if (!person) throw [{ code: T.EStatusCode.UNAUTHORIZED, message: 'Sign in first.' }]; const find = g.req.query.find ? (typeof g.req.query.find === 'string' ? JSON.parse(g.req.query.find) : g.req.query.find) : {}; g.req.query.find = { $and: [find, { country: person.country }] }; } module.exports = main; ``` Every row of the dataset is in India, like the person of the token, so the answer is the same ten rows as *get all*, after the hook ran. Before the benchmarks, a first hook adds a warning to the answer, to prove that the hooks of the table run ; then the hook above takes its place. ### The two tokens *Both tokens* means what a real application sends : the token of an API user and the token of a user of the application. - **`x-am-authorization`** : the token of an [API user](https://docs.apimaker.dev/v4/docs/apis-security/api-user-permission.html), from the [token API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-token-api.html). Its groups say which APIs it may call ; here one group allows everything. - **`x-am-user-authorization`** : the token of a row of the `customers` table, made by a [DB token generator](https://docs.apimaker.dev/v4/docs/authorization/AMDB.html) of the database (`first_name` as the user name, `last_name` as the password). Its `select` puts `customer_id` and `country` in `g.req.auth.authAMDB`, for the pre hook : a column which is not selected is not there. ```typescript import * as T from 'types'; let dbTokenGenerator: T.IAuthTokenAMDB = { name: 'bench_token_mongodb', instance: 'mongodb', database: 'am_bench', collection: 'customers', usernameColumn: 'first_name', passwordColumn: 'last_name', select: 'customer_id,country', expiresInSeconds: 2592000, runOnNativeProcess: false, }; module.exports = dbTokenGenerator; ``` Both tokens are asked for again before every run, and sent with every request. API Maker checks both on every request. ## The load For every API, on every database : 1. **Check** : one request checks the answer. Status 200 (201 for the insert), ten rows for *get all*, the row for *get by id*, the saved row for the insert. Before the first run, every API with tokens was also checked to answer 401 without its tokens, and with only one of them. 2. **Warm-up** : 5 seconds, so the cache fills, the connections to the database open, and the code of the custom API or the hook is loaded. 3. **Measure** : a pause of 3 seconds, then **15 seconds** of load, no pipelining : ```sh autocannon -c 100 -d 15 -w 4 -l "http://:38246/api/schema/bench/mongodb/am_bench/customers_public" autocannon -c 100 -d 15 -w 4 -l \ -H "x-am-authorization: " -H "x-am-user-authorization: " \ "http://:38246/api/schema/bench/mongodb/am_bench/customers" ``` 4. **Rest** : 15 seconds before the next API. All the APIs of a database run once (round 1), then again in reverse order (round 2), so a slow moment of a shared CPU does not fall on the same API twice. **The number shown is the average of the two rounds**, and the autocannon output shown is the round closer to it. The page of each server also shows both rounds and how far apart they are. *More connections* is a separate run of *get all, public* and *get by id with caching, public* on MongoDB : 15 seconds for each number of connections (10, 50, 100, 250, 500 and 1,000). ## Nothing else runs Before the APIs of a database are loaded : - the other benchmark databases are stopped (the MongoDB and Redis of API Maker keep running : API Maker needs them) ; - API Maker is restarted, so every database starts with a fresh process, and its two sandboxes are started and checked ; - the swap is emptied back into memory, when it fits. On the 1 vCPU server it did not fit before MySQL : MySQL 8.4, MongoDB, Redis, API Maker and its sandboxes need more than the 961 MB of that server, so its MySQL runs started with swap in use ; - the server rests 60 seconds : this is the memory *at rest* of the pages. Nothing else runs on the server : no reverse proxy, no admin panel open, no other load. The periodic jobs of Ubuntu (apt, man-db, sysstat, fstrim and the others) are stopped on both servers for the benchmarks. The job which rotates the log of API Maker, part of its installation, stays on. ## Memory and CPU A small script reads `/proc` and the cgroups of the containers once a second, on the server and on the load generator. It costs a few milliseconds of CPU a second. | Measure | What it is | |---|---| | API Maker | The resident memory (RSS) of the `api_maker_be` process, and its CPU in percent of one core. | | Containers | MongoDB, Redis, PostgreSQL, MySQL and the sandboxes : memory as `docker stats` counts it (without the inactive file cache), and CPU. | | Whole server | Memory used (total − available), swap used, pages swapped in and out. | | CPU | User, system, softirq, idle and **steal** : the time the hypervisor gave to other servers. On a shared CPU, steal shows whether a neighbour took the CPU during a run. | *Under load* on the pages is the most a part held while the APIs of its database ran, leaving out the first two seconds of each run, while autocannon opens its connections. *At rest* is the average of the 60 seconds before, with API Maker and its two sandboxes started and no request. ## What these numbers are not - **No HTTPS, no reverse proxy.** Caddy (which the installer puts in front by default) and TLS cost CPU of their own, on the same cores. - **A small table.** Ten rows of ten columns measure what API Maker adds to each request. Bigger answers cost more bytes, and more time in the database. - **Not your server.** Your CPU, your neighbours on a shared plan, your network and your data change the numbers. The method is here so you can measure your own. - **Not a published version.** The pages say API Maker 4.0.0 : the number of the build that was measured (commit `864bb64`, 12 October 2026), before the beta releases were numbered. - **Not a rule about shared and dedicated CPU.** Get all reached 4,692 req/s on 2 shared vCPUs and 3,712 on 2 dedicated vCPUs, on the same CPU model. A shared vCPU can run faster while its host is quiet, the two load generators differed (an EPYC 7713 and an EPYC 7642), and each server was measured once. Read a gap of this size as the spread of one run. Choose dedicated vCPUs for a speed which does not depend on the neighbours. ## Run it yourself 1. Make two servers in the same data centre. Install API Maker on the first one, and the databases you want to measure. 2. Load the [dataset](https://apimaker.dev/json/benchmark_dataset.json) into the tables above. Add an [instance](https://docs.apimaker.dev/v4/docs/apis-all/overview.html#instances) for each database, then the schemas, the settings, the token generators and the custom APIs of this page. 3. On the second server : `npm install autocannon@8`, ask for the two tokens with the [token API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-token-api.html), and run the commands of [The load](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html#the-load) for each API. The results : [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/index.html). --- # API Maker benchmark : 1 vCPU, 1 GB RAM (Linode shared CPU) > API Maker on 1 shared vCPU, 1 GB (Linode) : 2,435 req/s get all, 12,140 cached, on MongoDB, PostgreSQL and MySQL, with memory and autocannon output. Source: https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html Benchmark · Linode (Akamai Cloud) · Shared CPU · 12 October 2026 **1 vCPU, 1 GB RAM : 2,435 to 4,623 requests per second for a whole table.** API Maker 4.0.0 on the smallest Linode server, a Nanode 1 GB (g6-nanode-1) at $5 a month, its databases on the same machine. Every API was loaded for 15 seconds by autocannon from a second server, two times, on MongoDB, PostgreSQL and MySQL, public and with two tokens, while the server sampled the memory and CPU of every part each second. Get all · MongoDB 2,435req/s PostgreSQL 3,787 · MySQL 4,623 Get by id, cached 12,140req/s answered from Redis · PostgreSQL 12,083 · MySQL 12,193 Custom API · MongoDB 1,909req/s TypeScript, lean : run in the server · in the sandbox 1,389 API Maker memory 84MB at rest · 111 MB at most under load ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Nanode 1 GB (g6-nanode-1), shared cpu, $5 / month | | CPU | AMD EPYC 7642 48-Core Processor, 1 shared vCPU (KVM)
KVM guest, 1 thread per core · L1d 64 KiB (1 instance) · L2 512 KiB (1 instance) · L3 16 MiB (1 instance) · BogoMIPS 4600.00 | | Memory | 1 GB (961 MB usable), swap 2.5 GB (496 MB of Linode + 2 GB made by the installer) | | Disk, region | 25 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 864bb64 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer (lean code of the account runs in the server with QuickJS : sandbox.codeInServer), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) · PostgreSQL 18.6 (official image postgres:18, max_connections 500) · MySQL 8.4.11 (official image mysql:8.4, max_connections 500) : all on the same server | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 403 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default), each opening up to 1 runner when it is busy (one per vCPU) | | Load generator | Dedicated 8 GB (g6-dedicated-4) : AMD EPYC 7713 64-Core Processor, 4 dedicated vCPUs, Ubuntu 24.04.4 LTS, Node.js 24.21.0, autocannon 8.0.0 with 4 worker threads | | Network | Private network of the same data centre, round trip 0.45 ms (ping) | | Host | All seven servers were measured at the same time, each by a load generator of its own. | | Date | 12 October 2026, 05:30 to 07:05 UTC (its MongoDB block measured again from 06:46) | Only what a database needs was running while it was measured : API Maker and its two sandboxes, its MongoDB and Redis (API Maker always needs them) and the database under test. The other benchmark databases were stopped, API Maker was restarted and the swap emptied back into memory before each database, when it fitted there. How every number was taken : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/summary.html). ## The data Every table holds the ten rows of the [API Maker benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) : `https://apimaker.dev/json/benchmark_dataset.json`. Ten customers, ten columns each ; a *get all* answers all ten (2,418 bytes of JSON on MongoDB), a *get by id* one of them. | `_id` | `customer_id` | `first_name` | `last_name` | `phone` | `last_update` | `pincode` | `shipping_id` | `dob` | `country` | |---|---|---|---|---|---|---|---|---|---| | 60ae2488c37cd955cc144161 | 2 | NICK | WAHLBERG | 1123456789 | 2006-02-15T04:34:00.330Z | 111111 | 2 | 2022-10-30T03:25:03.000Z | India | | 60ae24c8c37cd955cc144162 | 1 | PENELOPE | GUINESS | 123456789 | 2006-02-15T04:34:00.330Z | 100050 | 1 | 2022-10-30T03:25:03.000Z | India | | 60ae247ac37cd955cc144160 | 3 | ED | CHASE | 2123456789 | 2006-02-15T04:34:00.330Z | 222222 | 3 | 2022-10-30T03:25:03.000Z | India | | 60ace1401efc56684403c68c | 4 | JENNIFER | DAVIS | 3123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 60accda51efc56684403c685 | 5 | JOHNNY | LOLLOBRIGIDA | 4123456789 | 2006-02-15T04:34:00.330Z | 485125 | 1 | 2022-10-30T03:25:03.000Z | India | | 606b7d364bebce00196eade7 | 6 | JOHNNY | LOLLOBRIGIDA | 5123456789 | 2006-02-15T04:34:00.330Z | 123456 | 2 | 2022-10-30T03:25:03.000Z | India | | 606b75961055000018fa9d98 | 7 | GRACE | MOSTEL | 6123456789 | 2006-02-15T04:34:00.330Z | 356589 | 3 | 2022-10-30T03:25:03.000Z | India | | 6064dd02730026001956663e | 8 | MATTHEW | JOHANSSON | 7123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 6064dcb8730026001956663c | 9 | JOE | SWANK | 8123456789 | 2006-02-15T04:34:00.330Z | 251415 | 1 | 2022-10-30T03:25:03.000Z | India | | 6064c4c02bafb90018955299 | 10 | CHRISTIAN | GABLE | 9123456789 | 2006-02-15T04:34:00.330Z | 100050 | | 2022-10-30T03:25:03.000Z | India | ## Results at a glance Requests per second, the average of two rounds of 15 seconds with 100 connections. *Public* APIs need no token ; *both tokens* means every request carries `x-am-authorization` (the token of an API user, whose groups decide what it may call) and `x-am-user-authorization` (the token of a row of the `customers` table, made by a DB token generator), and API Maker checks both. **Requests per second · 1 vCPU, 1 GB RAM, shared CPU** · MongoDB · PostgreSQL · MySQL Get allpublic · 2,435 · 3,787 · 4,623 Get allboth tokens · 2,439 · 3,560 · 4,126 Get all with cachingpublic · 11,054 · 11,064 · 11,245 Get all with cachingboth tokens · 8,709 · 8,797 · 8,870 Get all by streampublic · 2,545 · 3,989 · 4,213 Get all by streamboth tokens · 2,548 · 3,461 · 3,662 Custom API calling get all QuickJS · public · 1,909 · 2,178 · 2,419 Custom API calling get all QuickJS · both tokens · 1,699 · 2,016 · 2,231 Custom API in the sandbox Sandbox · public · 1,389 · 1,871 · 2,170 Get all with a pre hook QuickJS · both tokens · 1,984 · 2,318 · 2,688 Get by idpublic · 3,100 · 4,105 · 5,090 Get by idboth tokens · 3,044 · 3,887 · 4,526 Get by id with cachingpublic · 12,140 · 12,083 · 12,193 Get by id with cachingboth tokens · 9,481 · 9,402 · 9,217 Insert one rowpublic · 1,156 · 1,818 · 1,651 | API | Access | MongoDB | PostgreSQL | MySQL | |---|---|--:|--:|--:| | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all) | Public | **2,435** p99 46 ms | **3,787** p99 51 ms | **4,623** p99 27 ms | | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all) | Both tokens | **2,439** p99 52 ms | **3,560** p99 36 ms | **4,126** p99 31 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-caching) | Public | **11,054** p99 13 ms | **11,064** p99 13 ms | **11,245** p99 13 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-caching) | Both tokens | **8,709** p99 17 ms | **8,797** p99 17 ms | **8,870** p99 17 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-by-stream) | Public | **2,545** p99 46 ms | **3,989** p99 31 ms | **4,213** p99 29 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-by-stream) | Both tokens | **2,548** p99 54 ms | **3,461** p99 37 ms | **3,662** p99 34 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-calling-get-all) QuickJS | Public | **1,909** p99 69 ms | **2,178** p99 57 ms | **2,419** p99 51 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-calling-get-all) QuickJS | Both tokens | **1,699** p99 125 ms | **2,016** p99 57 ms | **2,231** p99 53 ms | | [Custom API in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-in-the-sandbox) Sandbox | Public | **1,389** p99 97 ms | **1,871** p99 100 ms | **2,170** p99 70 ms | | [Get all with a pre hook](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-all-with-a-pre-hook) QuickJS | Both tokens | **1,984** p99 66 ms | **2,318** p99 53 ms | **2,688** p99 47 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id) | Public | **3,100** p99 37 ms | **4,105** p99 31 ms | **5,090** p99 25 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id) | Both tokens | **3,044** p99 44 ms | **3,887** p99 32 ms | **4,526** p99 28 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id-with-caching) | Public | **12,140** p99 12 ms | **12,083** p99 12 ms | **12,193** p99 12 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#get-by-id-with-caching) | Both tokens | **9,481** p99 16 ms | **9,402** p99 16 ms | **9,217** p99 16 ms | | [Insert one row](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#insert-one-row) | Public | **1,156** p99 110 ms | **1,818** p99 64 ms | **1,651** p99 71 ms | | [Custom API without a database](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-without-a-database) | Public | **8,096** p99 18 ms | | | | [Custom API without a database, in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html#custom-api-without-a-database) | Public | **9,258** p99 17 ms | | | (0 errors) Every one of the **8,390,598 requests** of these runs was answered with status 200 or 201 : no error, no timeout. ## Memory What each part of the server held, in MB : at rest (the 60 seconds after API Maker and its sandboxes started, before any request) and under load. The bars show the second the whole server held the most memory while its database was loaded, out of the 961 MB of the server ; the table gives the most each part held on its own. API Maker is the resident memory of its process ; a container is counted the way `docker stats` counts it. With 961 MB for API Maker, its MongoDB, Redis, the database under test and two sandboxes, the server used its swap : up to 634 MB. Linux puts there the memory nothing touches, and takes it back when it is touched again. API Maker had up to 50 MB in swap, memory it holds but does not use while it serves requests, and kept as little as 44 MB in RAM. The rows *in swap* show what each part had there, the counts of pages swapped in and out are in the line under each run. Before MySQL, the swap could not be emptied : with it running, what the swap held did not fit in the memory of the server any more, and the runs of MySQL started with the swap in use. API Maker · MongoDB of API Maker · Redis · PostgreSQL / MySQL · Sandboxes · Linux, Docker, the rest · Available MongoDB at rest under load PostgreSQL at rest under load MySQL at rest under load | Part | MongoDB
at rest → under load | PostgreSQL
at rest → under load | MySQL
at rest → under load | |---|--:|--:|--:| | **API Maker** (process), in RAM | 84 → **111** | 88 → **105** | 76 → **88** | | … and in swap | 0 → **16** | 0 → **0** | 2 → **50** | | MongoDB of API Maker, in RAM | 217 → **231** | 215 → **215** | 73 → **81** | | … and in swap | 0 → **54** | 0 → **97** | 161 → **161** | | Redis, in RAM | 3 → **4** | 4 → **4** | 3 → **3** | | Database under test, in RAM | MongoDB above | 68 → **113** | 323 → **327** | | … and in swap | MongoDB above | 0 → **1** | 103 → **347** | | Sandboxes (2 containers), in RAM | 50 → **204** | 50 → **200** | 63 → **173** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **4** | | **Whole server**, RAM used | 686 → **807** | 716 → **770** | 764 → **775** | | Swap used | 1 → **90** | 1 → **136** | 342 → **634** | ## CPU On 1 vCPU, API Maker and the database share the same core : every request costs the work of both. During *get all, public*, the core was split this way (average of the 15 seconds, in vCPUs : 1.0 is the whole core ; a process counts its own kernel time) : | | MongoDB | PostgreSQL | MySQL | |---|--:|--:|--:| | API Maker | 0.4 vCPU | 0.4 vCPU | 0.5 vCPU | | The database | 0.5 vCPU | 0.4 vCPU | 0.4 vCPU | | MongoDB of API Maker (when it is not the one tested) | – | 0.0 vCPU | 0.0 vCPU | | Sandboxes (idle : no code runs in get all) | 0.0 vCPU | 0.0 vCPU | 0.0 vCPU | | Whole server busy (of its 1 vCPU) | 100 % | 100 % | 100 % | | … of which kernel time (network, disk), counted in the lines above too | 33 % | 35 % | 39 % | Steal time (CPU the hypervisor gave to other servers) was 0 % on average, 1 % at most. The load generator, sampled the same way, was never more than 40 % busy over its 4 cores : it was never the limit. ## Get all The schema API of a table answers all its rows : `GET /api/schema////
`. Every request reads the ten rows from the database, converts them with the schema of the table and sends them as JSON. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-api.html). ### Get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 2,435 37,654 requests in 15 s Latency p50 39ms average 39.3 ms Latency p99 46ms max 224 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,511** · 2 : **2,359** req/s · spread 6.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **97 MB** RSS · MongoDB **0.5 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **100 %**, of which kernel (network, disk) **33 %** · memory used **690 MB** of 961 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,787 56,194 requests in 15 s Latency p50 25ms average 26.2 ms Latency p99 51ms max 61 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,747** · 2 : **3,826** req/s · spread 2.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **96 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **100 %**, of which kernel (network, disk) **35 %** · memory used **737 MB** of 961 MB · steal **0 %** · swap **1511** pages moved autocannon · PostgreSQL · get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 4,623 70,425 requests in 15 s Latency p50 21ms average 20.8 ms Latency p99 27ms max 44 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,696** · 2 : **4,550** req/s · spread 3.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **83 MB** RSS (+ 12 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **73 MB** · whole server busy **100 %**, of which kernel (network, disk) **39 %** · memory used **775 MB** of 962 MB · steal **0 %** · swap **40** pages moved autocannon · MySQL · get all, public · round 1 of 2, the closer to the average ### Get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 2,439 37,858 requests in 15 s Latency p50 39ms average 39.1 ms Latency p99 52ms max 76 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,524** · 2 : **2,354** req/s · spread 7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **101 MB** RSS · MongoDB **0.4 vCPU** · sandboxes **0.0 vCPU**, **60 MB** · whole server busy **100 %**, of which kernel (network, disk) **31 %** · memory used **692 MB** of 961 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,560 52,112 requests in 15 s Latency p50 28ms average 28.3 ms Latency p99 36ms max 55 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,475** · 2 : **3,645** req/s · spread 4.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **97 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.3 vCPU** · sandboxes **0.0 vCPU**, **52 MB** · whole server busy **100 %**, of which kernel (network, disk) **32 %** · memory used **735 MB** of 961 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 4,126 63,281 requests in 15 s Latency p50 23ms average 23.2 ms Latency p99 31ms max 51 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,220** · 2 : **4,031** req/s · spread 4.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **84 MB** RSS (+ 12 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.3 vCPU** · sandboxes **0.0 vCPU**, **74 MB** · whole server busy **100 %**, of which kernel (network, disk) **37 %** · memory used **771 MB** of 962 MB · steal **0 %** · swap **188** pages moved autocannon · MySQL · get all, both tokens · round 1 of 2, the closer to the average ## Get all with caching The same request on a table whose API settings say `enableCaching: true`. The first answer is kept in Redis, under a key made of who asks and what is asked ; the next requests are answered from Redis until the answer expires or something writes the table. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get all with caching : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 11,054 163,851 requests in 15 s Latency p50 9ms average 8.7 ms Latency p99 13ms max 64 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **10,924** · 2 : **11,185** req/s · spread 2.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **99 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **60 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **47 %** · memory used **689 MB** of 962 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 11,064 166,921 requests in 15 s Latency p50 8ms average 8.5 ms Latency p99 13ms max 47 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **11,129** · 2 : **11,000** req/s · spread 1.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **96 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **52 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **47 %** · memory used **731 MB** of 962 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 11,245 167,442 requests in 15 s Latency p50 8ms average 8.5 ms Latency p99 13ms max 57 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **11,326** · 2 : **11,164** req/s · spread 1.4 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **48 MB** RSS (+ 50 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **173 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **46 %** · memory used **683 MB** of 962 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, public · round 2 of 2, the closer to the average ### Get all with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 8,709 128,865 requests in 15 s Latency p50 11ms average 11.2 ms Latency p99 17ms max 46 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,591** · 2 : **8,828** req/s · spread 2.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.8 vCPU**, **98 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **60 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **40 %** · memory used **680 MB** of 961 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 8,797 129,573 requests in 15 s Latency p50 11ms average 11.1 ms Latency p99 17ms max 48 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,955** · 2 : **8,639** req/s · spread 3.6 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.8 vCPU**, **96 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **200 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **39 %** · memory used **763 MB** of 962 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 8,870 131,305 requests in 15 s Latency p50 11ms average 10.9 ms Latency p99 17ms max 49 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,986** · 2 : **8,753** req/s · spread 2.6 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.8 vCPU**, **49 MB** RSS (+ 50 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **173 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **40 %** · memory used **682 MB** of 962 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, both tokens · round 2 of 2, the closer to the average ## Get all by stream `GET …/
/stream` : the rows are sent while they are read from the database cursor, so a large table never sits whole in memory. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-by-stream-api.html). ### Get all by stream : public No token : the API is public. Each answer : 2,477 bytes (MongoDB), status 200. **MongoDB** Requests / second 2,545 38,872 requests in 15 s Latency p50 38ms average 38.1 ms Latency p99 46ms max 78 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,498** · 2 : **2,592** req/s · spread 3.7 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **90 MB** RSS (+ 16 MB in swap) · MongoDB **0.4 vCPU** · sandboxes **0.0 vCPU**, **194 MB** · whole server busy **100 %**, of which kernel (network, disk) **30 %** · memory used **751 MB** of 962 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 3,989 61,363 requests in 15 s Latency p50 24ms average 23.9 ms Latency p99 31ms max 44 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,092** · 2 : **3,887** req/s · spread 5.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **96 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **52 MB** · whole server busy **100 %**, of which kernel (network, disk) **37 %** · memory used **731 MB** of 961 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, public · round 1 of 2, the closer to the average **MySQL** Requests / second 4,213 65,583 requests in 15 s Latency p50 22ms average 22.4 ms Latency p99 29ms max 53 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,373** · 2 : **4,052** req/s · spread 7.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **84 MB** RSS (+ 12 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.3 vCPU** · sandboxes **0.0 vCPU**, **74 MB** · whole server busy **100 %**, of which kernel (network, disk) **38 %** · memory used **769 MB** of 962 MB · steal **0 %** · swap **4** pages moved autocannon · MySQL · get all by stream, public · round 1 of 2, the closer to the average ### Get all by stream : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,577 bytes (MongoDB), status 200. **MongoDB** Requests / second 2,548 38,640 requests in 15 s Latency p50 39ms average 38.3 ms Latency p99 54ms max 80 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,577** · 2 : **2,519** req/s · spread 2.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **101 MB** RSS · MongoDB **0.4 vCPU** · sandboxes **0.0 vCPU**, **61 MB** · whole server busy **100 %**, of which kernel (network, disk) **29 %** · memory used **690 MB** of 962 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,461 50,678 requests in 15 s Latency p50 29ms average 29.1 ms Latency p99 37ms max 52 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,379** · 2 : **3,542** req/s · spread 4.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **97 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.3 vCPU** · sandboxes **0.0 vCPU**, **52 MB** · whole server busy **100 %**, of which kernel (network, disk) **34 %** · memory used **730 MB** of 962 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 3,662 55,776 requests in 15 s Latency p50 26ms average 26.4 ms Latency p99 34ms max 52 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,719** · 2 : **3,605** req/s · spread 3.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **84 MB** RSS (+ 12 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.3 vCPU** · sandboxes **0.0 vCPU**, **75 MB** · whole server busy **100 %**, of which kernel (network, disk) **35 %** · memory used **773 MB** of 962 MB · steal **0 %** · swap **20** pages moved autocannon · MySQL · get all by stream, both tokens · round 1 of 2, the closer to the average ## Custom API calling get all A custom API written in TypeScript, `return await g.sys.db.getAll({ instance, database, collection })`. This code is *lean* : it only reads what it is handed and asks `g.sys` for a read, so API Maker runs it in the server itself, with QuickJS, on the thread which answers the request, and the request never leaves the server. Code which needs more (a package, the time of the machine, `g.shared`, …) runs in the sandbox of the account : see the next API. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API (public : customers_public ; both tokens : customers)** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` ### Custom API calling get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 1,909 28,756 requests in 15 s Latency p50 53ms average 51.6 ms Latency p99 69ms max 96 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **1,917** · 2 : **1,901** req/s · spread 0.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.6 vCPU**, **108 MB** RSS · MongoDB **0.3 vCPU** · sandboxes **0.0 vCPU**, **61 MB** · whole server busy **100 %**, of which kernel (network, disk) **23 %** · memory used **695 MB** of 962 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 2,178 32,318 requests in 15 s Latency p50 46ms average 45.9 ms Latency p99 57ms max 84 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,155** · 2 : **2,201** req/s · spread 2.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **104 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.2 vCPU** · sandboxes **0.0 vCPU**, **52 MB** · whole server busy **100 %**, of which kernel (network, disk) **23 %** · memory used **734 MB** of 961 MB · steal **0 %** · swap **3219** pages moved autocannon · PostgreSQL · custom api calling get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 2,419 36,218 requests in 15 s Latency p50 41ms average 40.9 ms Latency p99 51ms max 68 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,415** · 2 : **2,423** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **88 MB** RSS (+ 20 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.2 vCPU** · sandboxes **0.0 vCPU**, **53 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **770 MB** of 962 MB · steal **0 %** · swap **2601** pages moved autocannon · MySQL · custom api calling get all, public · round 1 of 2, the closer to the average ### Custom API calling get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 1,699 24,489 requests in 15 s Latency p50 61ms average 60.7 ms Latency p99 125ms max 157 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **1,633** · 2 : **1,766** req/s · spread 7.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.6 vCPU**, **111 MB** RSS · MongoDB **0.3 vCPU** · sandboxes **0.0 vCPU**, **61 MB** · whole server busy **100 %**, of which kernel (network, disk) **23 %** · memory used **699 MB** of 962 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 2,016 31,030 requests in 15 s Latency p50 48ms average 47.8 ms Latency p99 57ms max 76 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **1,964** · 2 : **2,069** req/s · spread 5.2 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **99 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.2 vCPU** · sandboxes **0.0 vCPU**, **188 MB** · whole server busy **100 %**, of which kernel (network, disk) **22 %** · memory used **769 MB** of 961 MB · steal **0 %** · swap **23** pages moved autocannon · PostgreSQL · custom api calling get all, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 2,231 33,315 requests in 15 s Latency p50 44ms average 44.5 ms Latency p99 53ms max 68 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,222** · 2 : **2,240** req/s · spread 0.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **85 MB** RSS (+ 20 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.2 vCPU** · sandboxes **0.0 vCPU**, **53 MB** · whole server busy **100 %**, of which kernel (network, disk) **24 %** · memory used **762 MB** of 962 MB · steal **0 %** · swap **1** pages moved autocannon · MySQL · custom api calling get all, both tokens · round 1 of 2, the closer to the average ## Custom API in the sandbox The same custom API, with one line more : it reads `Date.now()`, the time of the machine, which lean code may not. So this code runs in a sandbox of the account (a container with Node.js 24) : the request goes from API Maker to a runner of the sandbox and back, and the rows are read from inside the sandbox by the core of API Maker loaded there. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API which runs in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const started = Date.now(); // the time of the machine : this code runs in the sandbox of the account return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 1,389 20,704 requests in 15 s Latency p50 75ms average 71.8 ms Latency p99 97ms max 126 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **1,380** · 2 : **1,397** req/s · spread 1.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.2 vCPU**, **104 MB** RSS · MongoDB **0.3 vCPU** · sandboxes **0.5 vCPU**, **204 MB** · whole server busy **100 %**, of which kernel (network, disk) **22 %** · memory used **807 MB** of 961 MB · steal **0 %** · swap **2180** pages moved autocannon · MongoDB · custom api in the sandbox, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 1,871 27,550 requests in 15 s Latency p50 52ms average 53.9 ms Latency p99 100ms max 151 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **1,837** · 2 : **1,905** req/s · spread 3.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.2 vCPU**, **99 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.2 vCPU** · sandboxes **0.4 vCPU**, **179 MB** · whole server busy **100 %**, of which kernel (network, disk) **24 %** · memory used **765 MB** of 962 MB · steal **0 %** · swap **7252** pages moved autocannon · PostgreSQL · custom api in the sandbox, public · round 1 of 2, the closer to the average **MySQL** Requests / second 2,170 33,456 requests in 15 s Latency p50 43ms average 44.3 ms Latency p99 70ms max 91 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,231** · 2 : **2,109** req/s · spread 5.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.3 vCPU**, **73 MB** RSS (+ 28 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.2 vCPU** · sandboxes **0.4 vCPU**, **155 MB** · whole server busy **100 %**, of which kernel (network, disk) **26 %** · memory used **752 MB** of 961 MB · steal **0 %** · swap **7405** pages moved autocannon · MySQL · custom api in the sandbox, public · round 1 of 2, the closer to the average ## Get all with a pre hook Get all, with both tokens, on a table whose get all API has a pre hook written in TypeScript : before the API, the hook runs (lean code : in the server, with QuickJS), reads the signed-in person from `x-am-user-authorization` and keeps the rows of their country (`g.req.query.find`), the row scoping most applications need. Every row of the dataset is in India, as the person is, so the answer is the same ten rows. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html). **The pre hook of SCHEMA_GET_ALL on customers_pre_hook** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { if (!g.req.isApiRequestFromUser) return; const person = g.req.auth.authAMDB; // the person, from x-am-user-authorization if (!person) throw [{ code: T.EStatusCode.UNAUTHORIZED, message: 'Sign in first.' }]; const find = g.req.query.find ? (typeof g.req.query.find === 'string' ? JSON.parse(g.req.query.find) : g.req.query.find) : {}; g.req.query.find = { $and: [find, { country: person.country }] }; } module.exports = main; ``` With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 1,984 29,638 requests in 15 s Latency p50 52ms average 50.1 ms Latency p99 66ms max 79 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **1,991** · 2 : **1,976** req/s · spread 0.8 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **103 MB** RSS (+ 1 MB in swap) · MongoDB **0.4 vCPU** · sandboxes **0.0 vCPU**, **112 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **717 MB** of 962 MB · steal **0 %** · swap **1** pages moved autocannon · MongoDB · get all with a pre hook, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 2,318 34,706 requests in 15 s Latency p50 42ms average 42.7 ms Latency p99 53ms max 68 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,314** · 2 : **2,321** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.6 vCPU**, **99 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.3 vCPU** · sandboxes **0.0 vCPU**, **179 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **765 MB** of 962 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 2,688 40,026 requests in 15 s Latency p50 37ms average 37.0 ms Latency p99 47ms max 67 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,669** · 2 : **2,707** req/s · spread 1.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.6 vCPU**, **74 MB** RSS (+ 28 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.2 vCPU** · sandboxes **0.0 vCPU**, **155 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **749 MB** of 961 MB · steal **0 %** · swap **550** pages moved autocannon · MySQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average ## Get by id One row by its primary key : `GET …/
/get-by-id/`. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-by-id-api.html). ### Get by id : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 3,100 46,704 requests in 15 s Latency p50 31ms average 31.6 ms Latency p99 37ms max 55 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,114** · 2 : **3,085** req/s · spread 0.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **101 MB** RSS (+ 1 MB in swap) · MongoDB **0.4 vCPU** · sandboxes **0.0 vCPU**, **201 MB** · whole server busy **100 %**, of which kernel (network, disk) **33 %** · memory used **797 MB** of 961 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 4,105 61,466 requests in 15 s Latency p50 24ms average 23.9 ms Latency p99 31ms max 47 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,099** · 2 : **4,112** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **98 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **179 MB** · whole server busy **100 %**, of which kernel (network, disk) **34 %** · memory used **765 MB** of 961 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, public · round 1 of 2, the closer to the average **MySQL** Requests / second 5,090 76,966 requests in 15 s Latency p50 19ms average 19.0 ms Latency p99 25ms max 56 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,132** · 2 : **5,048** req/s · spread 1.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **73 MB** RSS (+ 28 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.3 vCPU** · sandboxes **0.0 vCPU**, **155 MB** · whole server busy **100 %**, of which kernel (network, disk) **39 %** · memory used **740 MB** of 961 MB · steal **0 %** · swap **2** pages moved autocannon · MySQL · get by id, public · round 1 of 2, the closer to the average ### Get by id : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 3,044 45,922 requests in 15 s Latency p50 33ms average 32.1 ms Latency p99 44ms max 64 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,062** · 2 : **3,025** req/s · spread 1.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **101 MB** RSS (+ 1 MB in swap) · MongoDB **0.4 vCPU** · sandboxes **0.0 vCPU**, **112 MB** · whole server busy **100 %**, of which kernel (network, disk) **29 %** · memory used **747 MB** of 962 MB · steal **0 %** · swap **13** pages moved autocannon · MongoDB · get by id, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,887 58,517 requests in 15 s Latency p50 25ms average 25.1 ms Latency p99 32ms max 54 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,871** · 2 : **3,902** req/s · spread 0.8 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **100 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **131 MB** · whole server busy **100 %**, of which kernel (network, disk) **33 %** · memory used **728 MB** of 961 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 4,526 67,876 requests in 15 s Latency p50 21ms average 21.6 ms Latency p99 28ms max 56 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,525** · 2 : **4,527** req/s · spread 0 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **74 MB** RSS (+ 28 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.3 vCPU** · sandboxes **0.0 vCPU**, **155 MB** · whole server busy **100 %**, of which kernel (network, disk) **36 %** · memory used **740 MB** of 961 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, both tokens · round 1 of 2, the closer to the average ## Get by id with caching One row by its primary key, on a table with `enableCaching: true` : answered from Redis after the first request. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get by id with caching : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 12,140 185,403 requests in 15 s Latency p50 7ms average 7.6 ms Latency p99 12ms max 44 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **11,918** · 2 : **12,361** req/s · spread 3.6 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **99 MB** RSS (+ 1 MB in swap) · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **112 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **43 %** · memory used **711 MB** of 962 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 12,083 182,365 requests in 15 s Latency p50 8ms average 7.7 ms Latency p99 12ms max 57 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,159** · 2 : **12,008** req/s · spread 1.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **99 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **132 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **44 %** · memory used **712 MB** of 962 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 12,193 182,382 requests in 15 s Latency p50 8ms average 7.7 ms Latency p99 12ms max 42 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,226** · 2 : **12,159** req/s · spread 0.6 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **50 MB** RSS (+ 48 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **160 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **45 %** · memory used **684 MB** of 961 MB · steal **0 %** · swap **7** pages moved autocannon · MySQL · get by id with caching, public · round 2 of 2, the closer to the average ### Get by id with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 9,481 141,083 requests in 15 s Latency p50 10ms average 10.1 ms Latency p99 16ms max 42 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,405** · 2 : **9,557** req/s · spread 1.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.8 vCPU**, **99 MB** RSS (+ 1 MB in swap) · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **112 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **37 %** · memory used **718 MB** of 962 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 9,402 141,345 requests in 15 s Latency p50 10ms average 10.1 ms Latency p99 16ms max 46 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,424** · 2 : **9,380** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.8 vCPU**, **99 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **132 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **37 %** · memory used **713 MB** of 961 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 9,217 137,702 requests in 15 s Latency p50 10ms average 10.4 ms Latency p99 16ms max 45 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,254** · 2 : **9,181** req/s · spread 0.8 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.8 vCPU**, **50 MB** RSS (+ 48 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **151 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **38 %** · memory used **687 MB** of 961 MB · steal **0 %** · swap **1** pages moved autocannon · MySQL · get by id with caching, both tokens · round 2 of 2, the closer to the average ## Insert one row `POST …/
/save-single-or-multiple` with one row of 9 columns in the body : the schema checks and converts it, the database writes it, and the saved row is answered. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html). No token : the API is public. Each answer : 277 bytes (MongoDB), status 201. **MongoDB** Requests / second 1,156 17,847 requests in 15 s Latency p50 83ms average 83.3 ms Latency p99 110ms max 271 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **1,190** · 2 : **1,122** req/s · spread 5.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.3 vCPU**, **102 MB** RSS (+ 1 MB in swap) · MongoDB **0.5 vCPU** · sandboxes **0.0 vCPU**, **110 MB** · whole server busy **100 %**, of which kernel (network, disk) **30 %** · memory used **705 MB** of 961 MB · steal **0 %** · swap **232** pages moved autocannon · MongoDB · insert one row, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 1,818 27,416 requests in 15 s Latency p50 54ms average 54.1 ms Latency p99 64ms max 81 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **1,828** · 2 : **1,808** req/s · spread 1.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **100 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.5 vCPU** · sandboxes **0.0 vCPU**, **130 MB** · whole server busy **100 %**, of which kernel (network, disk) **35 %** · memory used **715 MB** of 962 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · insert one row, public · round 1 of 2, the closer to the average **MySQL** Requests / second 1,651 24,941 requests in 15 s Latency p50 59ms average 59.6 ms Latency p99 71ms max 86 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **1,640** · 2 : **1,663** req/s · spread 1.4 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.4 vCPU**, **52 MB** RSS (+ 48 MB in swap) · MongoDB **0.0 vCPU** · MySQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **150 MB** · whole server busy **100 %**, of which kernel (network, disk) **44 %** · memory used **686 MB** of 961 MB · steal **0 %** · swap **3725** pages moved autocannon · MySQL · insert one row, public · round 2 of 2, the closer to the average ## Custom API without a database A public custom API whose code returns a small object and reads no database : what running code of the account costs, without a database. Lean code runs in the server itself, with QuickJS ; the same code with `Date.now()` in it runs in a sandbox of the account : the trip from API Maker to the runner in its container and back. **In the server (lean code)** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from API Maker', time: 1 }; } module.exports = main; ``` Requests / second 8,096 120,920 requests in 15 s Latency p50 12ms average 12.0 ms Latency p99 18ms max 70 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,063** · 2 : **8,129** req/s · spread 0.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **93 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **162 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **704 MB** of 962 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the server (lean code) · round 1 of 2, the closer to the average **In the sandbox** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from the sandbox', time: Date.now() }; } module.exports = main; ``` Requests / second 9,258 135,661 requests in 15 s Latency p50 11ms average 10.6 ms Latency p99 17ms max 54 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,045** · 2 : **9,470** req/s · spread 4.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **96 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.3 vCPU**, **163 MB** · whole server busy **100 %**, of which kernel (network, disk) **26 %** · memory used **714 MB** of 962 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the sandbox · round 1 of 2, the closer to the average ## More connections *Get all, public* and *Get by id with caching, public* on MongoDB, one run of 15 seconds for each number of connections. More clients at once wait longer for their answer, and the server keeps answering them all. ### Get all, public, by connections **Get all, public, MongoDB : requests per second by connections** 10 connectionsp50 3 ms · p99 7 ms · 2,634 50 connectionsp50 19 ms · p99 24 ms · 2,566 100 connectionsp50 39 ms · p99 45 ms · 2,510 250 connectionsp50 97 ms · p99 108 ms · 2,549 500 connectionsp50 208 ms · p99 226 ms · 2,373 1,000 connectionsp50 413 ms · p99 441 ms · 2,395 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **2,634** | 3 ms | 7 ms | 14 ms | 0 | 100 % | 91 MB | | 50 | **2,566** | 19 ms | 24 ms | 33 ms | 0 | 100 % | 93 MB | | 100 | **2,510** | 39 ms | 45 ms | 70 ms | 0 | 100 % | 96 MB | | 250 | **2,549** | 97 ms | 108 ms | 398 ms | 0 | 100 % | 107 MB | | 500 | **2,373** | 208 ms | 226 ms | 458 ms | 0 | 100 % | 117 MB | | 1,000 | **2,395** | 413 ms | 441 ms | 616 ms | 0 | 100 % | 146 MB | ### Get by id with caching, public, by connections **Get by id with caching, public, MongoDB : requests per second by connections** 10 connectionsp50 1 ms · p99 2 ms · 8,594 50 connectionsp50 4 ms · p99 7 ms · 11,240 100 connectionsp50 8 ms · p99 12 ms · 12,096 250 connectionsp50 16 ms · p99 23 ms · 15,248 500 connectionsp50 34 ms · p99 51 ms · 13,336 1,000 connectionsp50 86 ms · p99 105 ms · 11,399 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **8,594** | 1 ms | 2 ms | 9 ms | 0 | 99 % | 88 MB | | 50 | **11,240** | 4 ms | 7 ms | 20 ms | 0 | 100 % | 83 MB | | 100 | **12,096** | 8 ms | 12 ms | 76 ms | 0 | 100 % | 85 MB | | 250 | **15,248** | 16 ms | 23 ms | 62 ms | 0 | 100 % | 91 MB | | 500 | **13,336** | 34 ms | 51 ms | 165 ms | 0 | 100 % | 103 MB | | 1,000 | **11,399** | 86 ms | 105 ms | 221 ms | 0 | 100 % | 126 MB | ## Questions ### How many requests per second can API Maker serve on 1 shared vCPU ? On this 1 GB server, with the database on the same machine : 2,435 requests per second for a whole table of ten rows on MongoDB (PostgreSQL 3,787 · MySQL 4,623), 3,100 for one row by its id, and 12,140 when the answer is cached in Redis. A custom API in TypeScript which reads the table answers 1,909 requests per second when API Maker runs it itself (lean code), 1,389 when it runs in the sandbox of the account. ### How much memory does API Maker use ? The API Maker process held 84 MB at rest and 111 MB at most under load on this server, in RAM. With the server short of memory, Linux moved up to 50 MB more of it to swap : memory API Maker holds but does not touch while it serves requests. The rest of the memory went to the databases (MongoDB, Redis, PostgreSQL or MySQL), the sandboxes which run the code of the account, and Linux itself. ### Do the two tokens slow the APIs down ? API Maker checks both tokens (x-am-authorization and x-am-user-authorization) and the groups of the API user on every request. Get all with both tokens answered 2,439 requests per second on MongoDB (public : 2,435), 3,560 requests per second on PostgreSQL (public : 3,787), 4,126 requests per second on MySQL (public : 4,623). The checks show most where the database does no work : a cached get all answered 8,709 requests per second with both tokens against 11,054 public on MongoDB. ### What does a pre hook cost ? A pre hook runs code of the account before the API ; a lean hook like this one runs in the server itself, with QuickJS. Get all with a row scoping pre hook answered 1,984 requests per second on MongoDB, against 2,439 for the same API without the hook. On 1 vCPU, the API, the hook and the database share the same core. ### Can I run these benchmarks myself ? Yes : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html) gives the dataset, the settings of every API and the exact autocannon commands. --- # API Maker benchmark : 2 vCPU, 4 GB RAM (Linode shared CPU) > API Maker on 2 shared vCPUs, 4 GB (Linode) : 4,692 req/s get all, 18,970 cached, on MongoDB, PostgreSQL and MySQL, with memory and autocannon output. Source: https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html Benchmark · Linode (Akamai Cloud) · Shared CPU · 12 October 2026 **2 vCPU, 4 GB RAM : 4,692 to 6,660 requests per second for a whole table.** API Maker 4.0.0 on a Linode 4 GB (g6-standard-2) : 2 shared vCPUs and 4 GB of RAM at $24 a month, its databases on the same machine. Every API was loaded for 15 seconds by autocannon from a second server, two times, on MongoDB, PostgreSQL and MySQL, public and with two tokens, while the server sampled the memory and CPU of every part each second. Get all · MongoDB 4,692req/s PostgreSQL 5,577 · MySQL 6,660 Get by id, cached 18,970req/s answered from Redis · PostgreSQL 19,622 · MySQL 19,858 Custom API · MongoDB 3,178req/s TypeScript, lean : run in the server · in the sandbox 3,015 API Maker memory 101MB at rest · 125 MB at most under load ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Linode 4 GB (g6-standard-2), shared cpu, $24 / month | | CPU | AMD EPYC 7642 48-Core Processor, 2 shared vCPUs (KVM)
KVM guest, 1 thread per core · L1d 128 KiB (2 instances) · L2 1 MiB (2 instances) · L3 32 MiB (2 instances) · BogoMIPS 4600.00 | | Memory | 4 GB (3,915 MB usable), swap 4.3 GB (496 MB of Linode + 3.8 GB made by the installer) | | Disk, region | 80 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 864bb64 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer (lean code of the account runs in the server with QuickJS : sandbox.codeInServer), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) · PostgreSQL 18.6 (official image postgres:18, max_connections 500) · MySQL 8.4.11 (official image mysql:8.4, max_connections 500) : all on the same server | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 403 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default), each opening up to 2 runners when it is busy (one per vCPU) | | Load generator | Dedicated 16 GB (g6-dedicated-8) : AMD EPYC 7713 64-Core Processor, 8 dedicated vCPUs, Ubuntu 24.04.4 LTS, Node.js 24.21.0, autocannon 8.0.0 with 5 worker threads | | Network | Private network of the same data centre, round trip 0.36 ms (ping) | | Host | A strict anti-affinity placement group kept the three shared CPU servers (2, 4 and 8 vCPUs) on three different hosts. All seven servers were measured at the same time, each by a load generator of its own. | | Date | 12 October 2026, 05:30 to 06:44 UTC | Only what a database needs was running while it was measured : API Maker and its two sandboxes, its MongoDB and Redis (API Maker always needs them) and the database under test. The other benchmark databases were stopped, API Maker was restarted and the swap emptied back into memory before each database, when it fitted there. How every number was taken : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/summary.html). ## The data Every table holds the ten rows of the [API Maker benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) : `https://apimaker.dev/json/benchmark_dataset.json`. Ten customers, ten columns each ; a *get all* answers all ten (2,418 bytes of JSON on MongoDB), a *get by id* one of them. | `_id` | `customer_id` | `first_name` | `last_name` | `phone` | `last_update` | `pincode` | `shipping_id` | `dob` | `country` | |---|---|---|---|---|---|---|---|---|---| | 60ae2488c37cd955cc144161 | 2 | NICK | WAHLBERG | 1123456789 | 2006-02-15T04:34:00.330Z | 111111 | 2 | 2022-10-30T03:25:03.000Z | India | | 60ae24c8c37cd955cc144162 | 1 | PENELOPE | GUINESS | 123456789 | 2006-02-15T04:34:00.330Z | 100050 | 1 | 2022-10-30T03:25:03.000Z | India | | 60ae247ac37cd955cc144160 | 3 | ED | CHASE | 2123456789 | 2006-02-15T04:34:00.330Z | 222222 | 3 | 2022-10-30T03:25:03.000Z | India | | 60ace1401efc56684403c68c | 4 | JENNIFER | DAVIS | 3123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 60accda51efc56684403c685 | 5 | JOHNNY | LOLLOBRIGIDA | 4123456789 | 2006-02-15T04:34:00.330Z | 485125 | 1 | 2022-10-30T03:25:03.000Z | India | | 606b7d364bebce00196eade7 | 6 | JOHNNY | LOLLOBRIGIDA | 5123456789 | 2006-02-15T04:34:00.330Z | 123456 | 2 | 2022-10-30T03:25:03.000Z | India | | 606b75961055000018fa9d98 | 7 | GRACE | MOSTEL | 6123456789 | 2006-02-15T04:34:00.330Z | 356589 | 3 | 2022-10-30T03:25:03.000Z | India | | 6064dd02730026001956663e | 8 | MATTHEW | JOHANSSON | 7123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 6064dcb8730026001956663c | 9 | JOE | SWANK | 8123456789 | 2006-02-15T04:34:00.330Z | 251415 | 1 | 2022-10-30T03:25:03.000Z | India | | 6064c4c02bafb90018955299 | 10 | CHRISTIAN | GABLE | 9123456789 | 2006-02-15T04:34:00.330Z | 100050 | | 2022-10-30T03:25:03.000Z | India | ## Results at a glance Requests per second, the average of two rounds of 15 seconds with 100 connections. *Public* APIs need no token ; *both tokens* means every request carries `x-am-authorization` (the token of an API user, whose groups decide what it may call) and `x-am-user-authorization` (the token of a row of the `customers` table, made by a DB token generator), and API Maker checks both. **Requests per second · 2 vCPU, 4 GB RAM, shared CPU** · MongoDB · PostgreSQL · MySQL Get allpublic · 4,692 · 5,577 · 6,660 Get allboth tokens · 4,425 · 5,290 · 5,902 Get all with cachingpublic · 18,195 · 17,836 · 18,227 Get all with cachingboth tokens · 14,144 · 14,083 · 13,394 Get all by streampublic · 4,548 · 5,866 · 5,815 Get all by streamboth tokens · 4,297 · 5,189 · 5,317 Custom API calling get all QuickJS · public · 3,178 · 3,806 · 4,090 Custom API calling get all QuickJS · both tokens · 2,957 · 3,461 · 3,666 Custom API in the sandbox Sandbox · public · 3,015 · 3,423 · 3,834 Get all with a pre hook QuickJS · both tokens · 3,339 · 3,884 · 4,389 Get by idpublic · 5,397 · 6,325 · 7,155 Get by idboth tokens · 4,947 · 5,739 · 6,551 Get by id with cachingpublic · 18,970 · 19,622 · 19,858 Get by id with cachingboth tokens · 14,695 · 14,989 · 15,385 Insert one rowpublic · 2,352 · 3,021 · 2,371 | API | Access | MongoDB | PostgreSQL | MySQL | |---|---|--:|--:|--:| | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all) | Public | **4,692** p99 40 ms | **5,577** p99 22 ms | **6,660** p99 17 ms | | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all) | Both tokens | **4,425** p99 38 ms | **5,290** p99 22 ms | **5,902** p99 20 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-caching) | Public | **18,195** p99 8 ms | **17,836** p99 8 ms | **18,227** p99 8 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-caching) | Both tokens | **14,144** p99 10 ms | **14,083** p99 12 ms | **13,394** p99 10 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-by-stream) | Public | **4,548** p99 39 ms | **5,866** p99 20 ms | **5,815** p99 21 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-by-stream) | Both tokens | **4,297** p99 39 ms | **5,189** p99 23 ms | **5,317** p99 22 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-calling-get-all) QuickJS | Public | **3,178** p99 50 ms | **3,806** p99 30 ms | **4,090** p99 28 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-calling-get-all) QuickJS | Both tokens | **2,957** p99 54 ms | **3,461** p99 32 ms | **3,666** p99 31 ms | | [Custom API in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-in-the-sandbox) Sandbox | Public | **3,015** p99 64 ms | **3,423** p99 51 ms | **3,834** p99 46 ms | | [Get all with a pre hook](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-all-with-a-pre-hook) QuickJS | Both tokens | **3,339** p99 50 ms | **3,884** p99 31 ms | **4,389** p99 27 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id) | Public | **5,397** p99 33 ms | **6,325** p99 19 ms | **7,155** p99 16 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id) | Both tokens | **4,947** p99 35 ms | **5,739** p99 21 ms | **6,551** p99 19 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id-with-caching) | Public | **18,970** p99 8 ms | **19,622** p99 7 ms | **19,858** p99 7 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#get-by-id-with-caching) | Both tokens | **14,695** p99 10 ms | **14,989** p99 10 ms | **15,385** p99 9 ms | | [Insert one row](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#insert-one-row) | Public | **2,352** p99 83 ms | **3,021** p99 38 ms | **2,371** p99 49 ms | | [Custom API without a database](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-without-a-database) | Public | **14,731** p99 10 ms | | | | [Custom API without a database, in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html#custom-api-without-a-database) | Public | **12,669** p99 12 ms | | | (0 errors) Every one of the **13,338,901 requests** of these runs was answered with status 200 or 201 : no error, no timeout. ## Memory What each part of the server held, in MB : at rest (the 60 seconds after API Maker and its sandboxes started, before any request) and under load. The bars show the second the whole server held the most memory while its database was loaded, out of the 3,915 MB of the server ; the table gives the most each part held on its own. API Maker is the resident memory of its process ; a container is counted the way `docker stats` counts it. API Maker · MongoDB of API Maker · Redis · PostgreSQL / MySQL · Sandboxes · Linux, Docker, the rest · Available MongoDB at rest under load PostgreSQL at rest under load MySQL at rest under load | Part | MongoDB
at rest → under load | PostgreSQL
at rest → under load | MySQL
at rest → under load | |---|--:|--:|--:| | **API Maker** (process), in RAM | 101 → **125** | 99 → **120** | 98 → **121** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | MongoDB of API Maker, in RAM | 125 → **265** | 255 → **255** | 255 → **255** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | Redis, in RAM | 3 → **4** | 3 → **3** | 3 → **3** | | Database under test, in RAM | MongoDB above | 42 → **150** | 424 → **495** | | … and in swap | MongoDB above | 0 → **0** | 0 → **0** | | Sandboxes (2 containers), in RAM | 50 → **394** | 50 → **226** | 50 → **256** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | **Whole server**, RAM used | 803 → **1321** | 1026 → **1297** | 1359 → **1658** | | Swap used | 0 → **0** | 0 → **0** | 0 → **0** | ## CPU On 2 vCPUs, API Maker, the database and the sandboxes share the same 2 vCPUs : every request costs the work of all of them. During *get all, public*, the CPU was split this way (average of the 15 seconds, in vCPUs : 2.0 is the whole server ; a process counts its own kernel time) : | | MongoDB | PostgreSQL | MySQL | |---|--:|--:|--:| | API Maker | 0.8 vCPU | 1.0 vCPU | 1.0 vCPU | | The database | 0.9 vCPU | 0.6 vCPU | 0.6 vCPU | | MongoDB of API Maker (when it is not the one tested) | – | 0.0 vCPU | 0.0 vCPU | | Sandboxes (idle : no code runs in get all) | 0.0 vCPU | 0.0 vCPU | 0.0 vCPU | | Whole server busy (of its 2 vCPUs) | 100 % | 97 % | 97 % | | … of which kernel time (network, disk), counted in the lines above too | 33 % | 37 % | 40 % | Steal time (CPU the hypervisor gave to other servers) was 0 % on average, 1 % at most. The load generator, sampled the same way, was never more than 29 % busy over its 8 cores : it was never the limit. ## Get all The schema API of a table answers all its rows : `GET /api/schema////
`. Every request reads the ten rows from the database, converts them with the schema of the table and sends them as JSON. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-api.html). ### Get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,692 72,620 requests in 15 s Latency p50 20ms average 20.4 ms Latency p99 40ms max 973 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,842** · 2 : **4,543** req/s · spread 6.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.8 vCPU**, **114 MB** RSS · MongoDB **0.9 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **100 %**, of which kernel (network, disk) **33 %** · memory used **854 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 5,577 81,663 requests in 15 s Latency p50 18ms average 17.9 ms Latency p99 22ms max 32 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,445** · 2 : **5,709** req/s · spread 4.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **109 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **97 %**, of which kernel (network, disk) **37 %** · memory used **1011 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 6,660 101,606 requests in 15 s Latency p50 14ms average 14.3 ms Latency p99 17ms max 30 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,774** · 2 : **6,545** req/s · spread 3.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **108 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **97 %**, of which kernel (network, disk) **40 %** · memory used **1372 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, public · round 1 of 2, the closer to the average ### Get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,425 66,986 requests in 15 s Latency p50 22ms average 21.9 ms Latency p99 38ms max 82 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,466** · 2 : **4,384** req/s · spread 1.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **115 MB** RSS · MongoDB **0.8 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **100 %**, of which kernel (network, disk) **31 %** · memory used **873 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 5,290 79,428 requests in 15 s Latency p50 18ms average 18.4 ms Latency p99 22ms max 29 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,283** · 2 : **5,296** req/s · spread 0.2 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.1 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.5 vCPU** · sandboxes **0.0 vCPU**, **226 MB** · whole server busy **98 %**, of which kernel (network, disk) **34 %** · memory used **1289 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 5,902 89,533 requests in 15 s Latency p50 16ms average 16.3 ms Latency p99 20ms max 30 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,835** · 2 : **5,970** req/s · spread 2.3 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.1 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.5 vCPU** · sandboxes **0.0 vCPU**, **256 MB** · whole server busy **98 %**, of which kernel (network, disk) **37 %** · memory used **1639 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, both tokens · round 2 of 2, the closer to the average ## Get all with caching The same request on a table whose API settings say `enableCaching: true`. The first answer is kept in Redis, under a key made of who asks and what is asked ; the next requests are answered from Redis until the answer expires or something writes the table. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get all with caching : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 18,195 275,330 requests in 15 s Latency p50 5ms average 5.0 ms Latency p99 8ms max 916 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **18,357** · 2 : **18,033** req/s · spread 1.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **113 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · Redis **0.1 vCPU** · whole server busy **99 %**, of which kernel (network, disk) **38 %** · memory used **824 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 17,836 268,807 requests in 15 s Latency p50 5ms average 5.1 ms Latency p99 8ms max 21 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **17,923** · 2 : **17,750** req/s · spread 1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **109 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · Redis **0.1 vCPU** · whole server busy **99 %**, of which kernel (network, disk) **37 %** · memory used **994 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 18,227 271,628 requests in 15 s Latency p50 5ms average 5.0 ms Latency p99 8ms max 37 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **18,345** · 2 : **18,109** req/s · spread 1.3 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **256 MB** · Redis **0.1 vCPU** · whole server busy **99 %**, of which kernel (network, disk) **38 %** · memory used **1643 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, public · round 2 of 2, the closer to the average ### Get all with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 14,144 211,670 requests in 15 s Latency p50 7ms average 6.6 ms Latency p99 10ms max 26 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **14,112** · 2 : **14,176** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **112 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **30 %** · memory used **815 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 14,083 209,102 requests in 15 s Latency p50 7ms average 6.7 ms Latency p99 12ms max 25 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,940** · 2 : **14,225** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **111 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **31 %** · memory used **999 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 13,394 209,487 requests in 15 s Latency p50 7ms average 6.7 ms Latency p99 10ms max 25 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,821** · 2 : **13,967** req/s · spread 8.6 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **256 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **31 %** · memory used **1640 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, both tokens · round 2 of 2, the closer to the average ## Get all by stream `GET …/
/stream` : the rows are sent while they are read from the database cursor, so a large table never sits whole in memory. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-by-stream-api.html). ### Get all by stream : public No token : the API is public. Each answer : 2,477 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,548 68,050 requests in 15 s Latency p50 21ms average 21.5 ms Latency p99 39ms max 104 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,538** · 2 : **4,559** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **117 MB** RSS · MongoDB **0.8 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **100 %**, of which kernel (network, disk) **30 %** · memory used **840 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 5,866 87,861 requests in 15 s Latency p50 17ms average 16.6 ms Latency p99 20ms max 31 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,858** · 2 : **5,873** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **97 %**, of which kernel (network, disk) **36 %** · memory used **1011 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, public · round 1 of 2, the closer to the average **MySQL** Requests / second 5,815 87,395 requests in 15 s Latency p50 17ms average 16.7 ms Latency p99 21ms max 29 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,827** · 2 : **5,803** req/s · spread 0.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.1 vCPU**, **110 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.5 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **97 %**, of which kernel (network, disk) **37 %** · memory used **1385 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, public · round 1 of 2, the closer to the average ### Get all by stream : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,577 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,297 64,395 requests in 15 s Latency p50 23ms average 22.8 ms Latency p99 39ms max 83 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,294** · 2 : **4,300** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **118 MB** RSS · MongoDB **0.8 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **100 %**, of which kernel (network, disk) **29 %** · memory used **844 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 5,189 76,903 requests in 15 s Latency p50 19ms average 19.0 ms Latency p99 23ms max 29 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,128** · 2 : **5,250** req/s · spread 2.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **98 %**, of which kernel (network, disk) **35 %** · memory used **1029 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 5,317 80,903 requests in 15 s Latency p50 18ms average 18.0 ms Latency p99 22ms max 29 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,240** · 2 : **5,394** req/s · spread 2.9 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.2 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.5 vCPU** · sandboxes **0.0 vCPU**, **256 MB** · whole server busy **98 %**, of which kernel (network, disk) **35 %** · memory used **1647 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, both tokens · round 2 of 2, the closer to the average ## Custom API calling get all A custom API written in TypeScript, `return await g.sys.db.getAll({ instance, database, collection })`. This code is *lean* : it only reads what it is handed and asks `g.sys` for a read, so API Maker runs it in the server itself, with QuickJS, on the thread which answers the request, and the request never leaves the server. Code which needs more (a package, the time of the machine, `g.shared`, …) runs in the sandbox of the account : see the next API. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API (public : customers_public ; both tokens : customers)** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` ### Custom API calling get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 3,178 48,380 requests in 15 s Latency p50 31ms average 30.5 ms Latency p99 50ms max 72 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,226** · 2 : **3,129** req/s · spread 3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.2 vCPU**, **122 MB** RSS · MongoDB **0.6 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **100 %**, of which kernel (network, disk) **23 %** · memory used **857 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,806 57,058 requests in 15 s Latency p50 26ms average 25.8 ms Latency p99 30ms max 43 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,804** · 2 : **3,809** req/s · spread 0.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **1030 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 4,090 61,892 requests in 15 s Latency p50 24ms average 23.7 ms Latency p99 28ms max 36 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,127** · 2 : **4,052** req/s · spread 1.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.4 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.3 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **100 %**, of which kernel (network, disk) **27 %** · memory used **1392 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, public · round 1 of 2, the closer to the average ### Custom API calling get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 2,957 44,841 requests in 15 s Latency p50 33ms average 32.9 ms Latency p99 54ms max 89 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,990** · 2 : **2,924** req/s · spread 2.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **123 MB** RSS · MongoDB **0.5 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **100 %**, of which kernel (network, disk) **22 %** · memory used **872 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,461 52,752 requests in 15 s Latency p50 28ms average 27.9 ms Latency p99 32ms max 44 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,517** · 2 : **3,404** req/s · spread 3.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.4 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **100 %**, of which kernel (network, disk) **23 %** · memory used **1032 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 3,666 55,253 requests in 15 s Latency p50 27ms average 26.6 ms Latency p99 31ms max 41 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,648** · 2 : **3,684** req/s · spread 1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.4 vCPU**, **119 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.3 vCPU** · sandboxes **0.0 vCPU**, **256 MB** · whole server busy **100 %**, of which kernel (network, disk) **24 %** · memory used **1635 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, both tokens · round 2 of 2, the closer to the average ## Custom API in the sandbox The same custom API, with one line more : it reads `Date.now()`, the time of the machine, which lean code may not. So this code runs in a sandbox of the account (a container with Node.js 24) : the request goes from API Maker to a runner of the sandbox and back, and the rows are read from inside the sandbox by the core of API Maker loaded there. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API which runs in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const started = Date.now(); // the time of the machine : this code runs in the sandbox of the account return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 3,015 46,302 requests in 15 s Latency p50 31ms average 31.8 ms Latency p99 64ms max 217 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,087** · 2 : **2,943** req/s · spread 4.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **118 MB** RSS · MongoDB **0.6 vCPU** · sandboxes **0.9 vCPU**, **387 MB** · whole server busy **100 %**, of which kernel (network, disk) **22 %** · memory used **1229 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api in the sandbox, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,423 51,323 requests in 15 s Latency p50 28ms average 28.7 ms Latency p99 51ms max 75 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,424** · 2 : **3,422** req/s · spread 0.1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **115 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.4 vCPU** · sandboxes **0.8 vCPU**, **219 MB** · whole server busy **100 %**, of which kernel (network, disk) **26 %** · memory used **1285 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api in the sandbox, public · round 2 of 2, the closer to the average **MySQL** Requests / second 3,834 58,137 requests in 15 s Latency p50 25ms average 25.3 ms Latency p99 46ms max 80 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,876** · 2 : **3,792** req/s · spread 2.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.6 vCPU**, **112 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.3 vCPU** · sandboxes **0.8 vCPU**, **224 MB** · whole server busy **100 %**, of which kernel (network, disk) **28 %** · memory used **1589 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api in the sandbox, public · round 1 of 2, the closer to the average ## Get all with a pre hook Get all, with both tokens, on a table whose get all API has a pre hook written in TypeScript : before the API, the hook runs (lean code : in the server, with QuickJS), reads the signed-in person from `x-am-user-authorization` and keeps the rows of their country (`g.req.query.find`), the row scoping most applications need. Every row of the dataset is in India, as the person is, so the answer is the same ten rows. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html). **The pre hook of SCHEMA_GET_ALL on customers_pre_hook** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { if (!g.req.isApiRequestFromUser) return; const person = g.req.auth.authAMDB; // the person, from x-am-user-authorization if (!person) throw [{ code: T.EStatusCode.UNAUTHORIZED, message: 'Sign in first.' }]; const find = g.req.query.find ? (typeof g.req.query.find === 'string' ? JSON.parse(g.req.query.find) : g.req.query.find) : {}; g.req.query.find = { $and: [find, { country: person.country }] }; } module.exports = main; ``` With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 3,339 49,908 requests in 15 s Latency p50 29ms average 29.5 ms Latency p99 50ms max 107 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,328** · 2 : **3,350** req/s · spread 0.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.1 vCPU**, **121 MB** RSS · MongoDB **0.7 vCPU** · sandboxes **0.0 vCPU**, **393 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **1268 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,884 58,349 requests in 15 s Latency p50 25ms average 25.2 ms Latency p99 31ms max 39 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,890** · 2 : **3,878** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.2 vCPU**, **115 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.5 vCPU** · sandboxes **0.0 vCPU**, **214 MB** · whole server busy **99 %**, of which kernel (network, disk) **27 %** · memory used **1251 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 4,389 65,180 requests in 15 s Latency p50 22ms average 22.5 ms Latency p99 27ms max 37 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,346** · 2 : **4,433** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **114 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **225 MB** · whole server busy **99 %**, of which kernel (network, disk) **28 %** · memory used **1603 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average ## Get by id One row by its primary key : `GET …/
/get-by-id/`. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-by-id-api.html). ### Get by id : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 5,397 80,537 requests in 15 s Latency p50 18ms average 18.1 ms Latency p99 33ms max 87 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,370** · 2 : **5,425** req/s · spread 1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **120 MB** RSS · MongoDB **0.8 vCPU** · sandboxes **0.0 vCPU**, **392 MB** · whole server busy **100 %**, of which kernel (network, disk) **32 %** · memory used **1224 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 6,325 95,917 requests in 15 s Latency p50 15ms average 15.1 ms Latency p99 19ms max 26 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,395** · 2 : **6,254** req/s · spread 2.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **114 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **213 MB** · whole server busy **97 %**, of which kernel (network, disk) **36 %** · memory used **1248 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, public · round 1 of 2, the closer to the average **MySQL** Requests / second 7,155 108,530 requests in 15 s Latency p50 13ms average 13.3 ms Latency p99 16ms max 28 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,236** · 2 : **7,075** req/s · spread 2.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **114 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.5 vCPU** · sandboxes **0.0 vCPU**, **225 MB** · whole server busy **97 %**, of which kernel (network, disk) **40 %** · memory used **1598 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, public · round 1 of 2, the closer to the average ### Get by id : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,947 73,552 requests in 15 s Latency p50 20ms average 19.9 ms Latency p99 35ms max 63 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,904** · 2 : **4,990** req/s · spread 1.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **121 MB** RSS · MongoDB **0.7 vCPU** · sandboxes **0.0 vCPU**, **392 MB** · whole server busy **100 %**, of which kernel (network, disk) **31 %** · memory used **1234 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 5,739 86,110 requests in 15 s Latency p50 17ms average 16.9 ms Latency p99 21ms max 33 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,742** · 2 : **5,736** req/s · spread 0.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **115 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **213 MB** · whole server busy **97 %**, of which kernel (network, disk) **33 %** · memory used **1258 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 6,551 96,599 requests in 15 s Latency p50 15ms average 15.0 ms Latency p99 19ms max 28 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,440** · 2 : **6,661** req/s · spread 3.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.1 vCPU**, **115 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.5 vCPU** · sandboxes **0.0 vCPU**, **225 MB** · whole server busy **97 %**, of which kernel (network, disk) **35 %** · memory used **1596 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, both tokens · round 1 of 2, the closer to the average ## Get by id with caching One row by its primary key, on a table with `enableCaching: true` : answered from Redis after the first request. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get by id with caching : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 18,970 279,999 requests in 15 s Latency p50 5ms average 4.9 ms Latency p99 8ms max 36 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **18,666** · 2 : **19,274** req/s · spread 3.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **120 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **265 MB** · Redis **0.1 vCPU** · whole server busy **99 %**, of which kernel (network, disk) **30 %** · memory used **1082 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 19,622 293,227 requests in 15 s Latency p50 5ms average 4.6 ms Latency p99 7ms max 21 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **19,694** · 2 : **19,549** req/s · spread 0.7 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **115 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **212 MB** · Redis **0.1 vCPU** · whole server busy **99 %**, of which kernel (network, disk) **32 %** · memory used **1263 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, public · round 2 of 2, the closer to the average **MySQL** Requests / second 19,858 299,686 requests in 15 s Latency p50 4ms average 4.5 ms Latency p99 7ms max 25 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **19,737** · 2 : **19,979** req/s · spread 1.2 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **113 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **225 MB** · Redis **0.1 vCPU** · whole server busy **99 %**, of which kernel (network, disk) **33 %** · memory used **1606 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, public · round 2 of 2, the closer to the average ### Get by id with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 14,695 225,961 requests in 15 s Latency p50 6ms average 6.1 ms Latency p99 10ms max 45 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **15,064** · 2 : **14,326** req/s · spread 5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **265 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **29 %** · memory used **1072 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 14,989 227,593 requests in 15 s Latency p50 6ms average 6.1 ms Latency p99 10ms max 22 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **15,173** · 2 : **14,806** req/s · spread 2.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **114 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **213 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **28 %** · memory used **1245 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 15,385 228,326 requests in 15 s Latency p50 6ms average 6.1 ms Latency p99 9ms max 24 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **15,223** · 2 : **15,548** req/s · spread 2.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **113 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **225 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **29 %** · memory used **1587 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, both tokens · round 1 of 2, the closer to the average ## Insert one row `POST …/
/save-single-or-multiple` with one row of 9 columns in the body : the schema checks and converts it, the database writes it, and the saved row is answered. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html). No token : the API is public. Each answer : 277 bytes (MongoDB), status 201. **MongoDB** Requests / second 2,352 36,270 requests in 15 s Latency p50 38ms average 40.8 ms Latency p99 83ms max 167 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,419** · 2 : **2,285** req/s · spread 5.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.6 vCPU**, **122 MB** RSS · MongoDB **1.1 vCPU** · sandboxes **0.0 vCPU**, **264 MB** · whole server busy **99 %**, of which kernel (network, disk) **31 %** · memory used **1130 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · insert one row, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,021 45,251 requests in 15 s Latency p50 33ms average 32.6 ms Latency p99 38ms max 49 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,017** · 2 : **3,024** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.8 vCPU** · sandboxes **0.0 vCPU**, **213 MB** · whole server busy **95 %**, of which kernel (network, disk) **35 %** · memory used **1254 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · insert one row, public · round 1 of 2, the closer to the average **MySQL** Requests / second 2,371 36,182 requests in 15 s Latency p50 41ms average 40.9 ms Latency p99 49ms max 59 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,329** · 2 : **2,413** req/s · spread 3.5 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.6 vCPU**, **115 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **225 MB** · whole server busy **91 %**, of which kernel (network, disk) **39 %** · memory used **1603 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · insert one row, public · round 2 of 2, the closer to the average ## Custom API without a database A public custom API whose code returns a small object and reads no database : what running code of the account costs, without a database. Lean code runs in the server itself, with QuickJS ; the same code with `Date.now()` in it runs in a sandbox of the account : the trip from API Maker to the runner in its container and back. **In the server (lean code)** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from API Maker', time: 1 }; } module.exports = main; ``` Requests / second 14,731 222,686 requests in 15 s Latency p50 6ms average 6.2 ms Latency p99 10ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **14,847** · 2 : **14,615** req/s · spread 1.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **115 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **392 MB** · whole server busy **100 %**, of which kernel (network, disk) **22 %** · memory used **1281 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the server (lean code) · round 1 of 2, the closer to the average **In the sandbox** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from the sandbox', time: Date.now() }; } module.exports = main; ``` Requests / second 12,669 190,003 requests in 15 s Latency p50 7ms average 7.4 ms Latency p99 12ms max 24 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,670** · 2 : **12,668** req/s · spread 0 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.4 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.5 vCPU**, **392 MB** · whole server busy **99 %**, of which kernel (network, disk) **26 %** · memory used **1308 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the sandbox · round 2 of 2, the closer to the average ## More connections *Get all, public* and *Get by id with caching, public* on MongoDB, one run of 15 seconds for each number of connections. More clients at once wait longer for their answer, and the server keeps answering them all. ### Get all, public, by connections **Get all, public, MongoDB : requests per second by connections** 10 connectionsp50 2 ms · p99 4 ms · 4,202 50 connectionsp50 10 ms · p99 20 ms · 4,614 100 connectionsp50 20 ms · p99 50 ms · 4,707 250 connectionsp50 57 ms · p99 75 ms · 4,329 500 connectionsp50 110 ms · p99 130 ms · 4,494 1,000 connectionsp50 221 ms · p99 245 ms · 4,488 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **4,202** | 2 ms | 4 ms | 10 ms | 0 | 96 % | 114 MB | | 50 | **4,614** | 10 ms | 20 ms | 44 ms | 0 | 100 % | 117 MB | | 100 | **4,707** | 20 ms | 50 ms | 113 ms | 0 | 100 % | 121 MB | | 250 | **4,329** | 57 ms | 75 ms | 137 ms | 0 | 100 % | 134 MB | | 500 | **4,494** | 110 ms | 130 ms | 226 ms | 0 | 100 % | 148 MB | | 1,000 | **4,488** | 221 ms | 245 ms | 319 ms | 0 | 100 % | 182 MB | ### Get by id with caching, public, by connections **Get by id with caching, public, MongoDB : requests per second by connections** 10 connectionsp50 0 ms · p99 1 ms · 10,987 50 connectionsp50 2 ms · p99 4 ms · 17,994 100 connectionsp50 5 ms · p99 7 ms · 19,413 250 connectionsp50 11 ms · p99 17 ms · 21,461 500 connectionsp50 24 ms · p99 30 ms · 20,182 1,000 connectionsp50 55 ms · p99 63 ms · 17,904 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **10,987** | 0 ms | 1 ms | 10 ms | 0 | 83 % | 120 MB | | 50 | **17,994** | 2 ms | 4 ms | 19 ms | 0 | 98 % | 119 MB | | 100 | **19,413** | 5 ms | 7 ms | 23 ms | 0 | 99 % | 121 MB | | 250 | **21,461** | 11 ms | 17 ms | 44 ms | 0 | 100 % | 131 MB | | 500 | **20,182** | 24 ms | 30 ms | 67 ms | 0 | 100 % | 146 MB | | 1,000 | **17,904** | 55 ms | 63 ms | 143 ms | 0 | 100 % | 173 MB | ## Questions ### How many requests per second can API Maker serve on 2 shared vCPUs ? On this 4 GB server, with the database on the same machine : 4,692 requests per second for a whole table of ten rows on MongoDB (PostgreSQL 5,577 · MySQL 6,660), 5,397 for one row by its id, and 18,970 when the answer is cached in Redis. A custom API in TypeScript which reads the table answers 3,178 requests per second when API Maker runs it itself (lean code), 3,015 when it runs in the sandbox of the account. ### How much memory does API Maker use ? The API Maker process held 101 MB at rest and 125 MB at most under load on this server, in RAM. The rest of the memory went to the databases (MongoDB, Redis, PostgreSQL or MySQL), the sandboxes which run the code of the account, and Linux itself. ### Do the two tokens slow the APIs down ? API Maker checks both tokens (x-am-authorization and x-am-user-authorization) and the groups of the API user on every request. Get all with both tokens answered 4,425 requests per second on MongoDB (public : 4,692), 5,290 requests per second on PostgreSQL (public : 5,577), 5,902 requests per second on MySQL (public : 6,660). The checks show most where the database does no work : a cached get all answered 14,144 requests per second with both tokens against 18,195 public on MongoDB. ### What does a pre hook cost ? A pre hook runs code of the account before the API ; a lean hook like this one runs in the server itself, with QuickJS. Get all with a row scoping pre hook answered 3,339 requests per second on MongoDB, against 4,425 for the same API without the hook. On 2 vCPUs, the API, the hook and the database share the same 2 vCPUs. ### Can I run these benchmarks myself ? Yes : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html) gives the dataset, the settings of every API and the exact autocannon commands. --- # API Maker benchmark : 4 vCPU, 8 GB RAM (Linode shared CPU) > API Maker on 4 shared vCPUs, 8 GB (Linode) : 7,423 req/s get all, 26,444 cached, on MongoDB, PostgreSQL and MySQL, with memory and autocannon output. Source: https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html Benchmark · Linode (Akamai Cloud) · Shared CPU · 12 October 2026 **4 vCPU, 8 GB RAM : 7,423 to 9,375 requests per second for a whole table.** API Maker 4.0.0 on a Linode 8 GB (g6-standard-4) : 4 shared vCPUs and 8 GB of RAM at $48 a month, its databases on the same machine. Every API was loaded for 15 seconds by autocannon from a second server, two times, on MongoDB, PostgreSQL and MySQL, public and with two tokens, while the server sampled the memory and CPU of every part each second. Get all · MongoDB 7,423req/s PostgreSQL 8,395 · MySQL 9,375 Get by id, cached 26,444req/s answered from Redis · PostgreSQL 26,617 · MySQL 27,185 Custom API · MongoDB 5,178req/s TypeScript, lean : run in the server · in the sandbox 4,649 API Maker memory 109MB at rest · 142 MB at most under load ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Linode 8 GB (g6-standard-4), shared cpu, $48 / month | | CPU | AMD EPYC 7642 48-Core Processor, 4 shared vCPUs (KVM)
KVM guest, 1 thread per core · L1d 256 KiB (4 instances) · L2 2 MiB (4 instances) · L3 64 MiB (4 instances) · BogoMIPS 4599.99 | | Memory | 8 GB (7,941 MB usable), swap 8.3 GB (496 MB of Linode + 7.8 GB made by the installer) | | Disk, region | 160 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 864bb64 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer (lean code of the account runs in the server with QuickJS : sandbox.codeInServer), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) · PostgreSQL 18.6 (official image postgres:18, max_connections 500) · MySQL 8.4.11 (official image mysql:8.4, max_connections 500) : all on the same server | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 403 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default), each opening up to 4 runners when it is busy (one per vCPU) | | Load generator | Dedicated 32 GB (g6-dedicated-16) : AMD EPYC 7713 64-Core Processor, 16 dedicated vCPUs, Ubuntu 24.04.4 LTS, Node.js 24.21.0, autocannon 8.0.0 with 10 worker threads | | Network | Private network of the same data centre, round trip 0.42 ms (ping) | | Host | A strict anti-affinity placement group kept the three shared CPU servers (2, 4 and 8 vCPUs) on three different hosts. All seven servers were measured at the same time, each by a load generator of its own. | | Date | 12 October 2026, 05:30 to 06:44 UTC | Only what a database needs was running while it was measured : API Maker and its two sandboxes, its MongoDB and Redis (API Maker always needs them) and the database under test. The other benchmark databases were stopped, API Maker was restarted and the swap emptied back into memory before each database, when it fitted there. How every number was taken : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/summary.html). ## The data Every table holds the ten rows of the [API Maker benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) : `https://apimaker.dev/json/benchmark_dataset.json`. Ten customers, ten columns each ; a *get all* answers all ten (2,418 bytes of JSON on MongoDB), a *get by id* one of them. | `_id` | `customer_id` | `first_name` | `last_name` | `phone` | `last_update` | `pincode` | `shipping_id` | `dob` | `country` | |---|---|---|---|---|---|---|---|---|---| | 60ae2488c37cd955cc144161 | 2 | NICK | WAHLBERG | 1123456789 | 2006-02-15T04:34:00.330Z | 111111 | 2 | 2022-10-30T03:25:03.000Z | India | | 60ae24c8c37cd955cc144162 | 1 | PENELOPE | GUINESS | 123456789 | 2006-02-15T04:34:00.330Z | 100050 | 1 | 2022-10-30T03:25:03.000Z | India | | 60ae247ac37cd955cc144160 | 3 | ED | CHASE | 2123456789 | 2006-02-15T04:34:00.330Z | 222222 | 3 | 2022-10-30T03:25:03.000Z | India | | 60ace1401efc56684403c68c | 4 | JENNIFER | DAVIS | 3123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 60accda51efc56684403c685 | 5 | JOHNNY | LOLLOBRIGIDA | 4123456789 | 2006-02-15T04:34:00.330Z | 485125 | 1 | 2022-10-30T03:25:03.000Z | India | | 606b7d364bebce00196eade7 | 6 | JOHNNY | LOLLOBRIGIDA | 5123456789 | 2006-02-15T04:34:00.330Z | 123456 | 2 | 2022-10-30T03:25:03.000Z | India | | 606b75961055000018fa9d98 | 7 | GRACE | MOSTEL | 6123456789 | 2006-02-15T04:34:00.330Z | 356589 | 3 | 2022-10-30T03:25:03.000Z | India | | 6064dd02730026001956663e | 8 | MATTHEW | JOHANSSON | 7123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 6064dcb8730026001956663c | 9 | JOE | SWANK | 8123456789 | 2006-02-15T04:34:00.330Z | 251415 | 1 | 2022-10-30T03:25:03.000Z | India | | 6064c4c02bafb90018955299 | 10 | CHRISTIAN | GABLE | 9123456789 | 2006-02-15T04:34:00.330Z | 100050 | | 2022-10-30T03:25:03.000Z | India | ## Results at a glance Requests per second, the average of two rounds of 15 seconds with 100 connections. *Public* APIs need no token ; *both tokens* means every request carries `x-am-authorization` (the token of an API user, whose groups decide what it may call) and `x-am-user-authorization` (the token of a row of the `customers` table, made by a DB token generator), and API Maker checks both. **Requests per second · 4 vCPU, 8 GB RAM, shared CPU** · MongoDB · PostgreSQL · MySQL Get allpublic · 7,423 · 8,395 · 9,375 Get allboth tokens · 7,021 · 7,680 · 8,338 Get all with cachingpublic · 26,115 · 26,420 · 25,630 Get all with cachingboth tokens · 20,550 · 20,113 · 20,763 Get all by streampublic · 6,724 · 8,226 · 8,355 Get all by streamboth tokens · 6,737 · 7,486 · 7,469 Custom API calling get all QuickJS · public · 5,178 · 5,658 · 6,016 Custom API calling get all QuickJS · both tokens · 4,910 · 5,158 · 5,536 Custom API in the sandbox Sandbox · public · 4,649 · 5,126 · 5,486 Get all with a pre hook QuickJS · both tokens · 5,327 · 6,151 · 6,768 Get by idpublic · 8,076 · 9,446 · 9,893 Get by idboth tokens · 7,513 · 8,233 · 8,892 Get by id with cachingpublic · 26,444 · 26,617 · 27,185 Get by id with cachingboth tokens · 20,887 · 21,238 · 22,684 Insert one rowpublic · 3,198 · 3,969 · 3,181 | API | Access | MongoDB | PostgreSQL | MySQL | |---|---|--:|--:|--:| | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all) | Public | **7,423** p99 28 ms | **8,395** p99 14 ms | **9,375** p99 12 ms | | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all) | Both tokens | **7,021** p99 28 ms | **7,680** p99 15 ms | **8,338** p99 17 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-caching) | Public | **26,115** p99 5 ms | **26,420** p99 5 ms | **25,630** p99 6 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-caching) | Both tokens | **20,550** p99 7 ms | **20,113** p99 8 ms | **20,763** p99 7 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-by-stream) | Public | **6,724** p99 33 ms | **8,226** p99 14 ms | **8,355** p99 14 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-by-stream) | Both tokens | **6,737** p99 29 ms | **7,486** p99 15 ms | **7,469** p99 15 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-calling-get-all) QuickJS | Public | **5,178** p99 34 ms | **5,658** p99 20 ms | **6,016** p99 19 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-calling-get-all) QuickJS | Both tokens | **4,910** p99 34 ms | **5,158** p99 22 ms | **5,536** p99 20 ms | | [Custom API in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-in-the-sandbox) Sandbox | Public | **4,649** p99 42 ms | **5,126** p99 35 ms | **5,486** p99 33 ms | | [Get all with a pre hook](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-all-with-a-pre-hook) QuickJS | Both tokens | **5,327** p99 34 ms | **6,151** p99 18 ms | **6,768** p99 17 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id) | Public | **8,076** p99 26 ms | **9,446** p99 12 ms | **9,893** p99 11 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id) | Both tokens | **7,513** p99 23 ms | **8,233** p99 17 ms | **8,892** p99 13 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id-with-caching) | Public | **26,444** p99 5 ms | **26,617** p99 5 ms | **27,185** p99 5 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#get-by-id-with-caching) | Both tokens | **20,887** p99 7 ms | **21,238** p99 7 ms | **22,684** p99 6 ms | | [Insert one row](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#insert-one-row) | Public | **3,198** p99 63 ms | **3,969** p99 28 ms | **3,181** p99 35 ms | | [Custom API without a database](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-without-a-database) | Public | **26,046** p99 6 ms | | | | [Custom API without a database, in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html#custom-api-without-a-database) | Public | **17,702** p99 10 ms | | | (0 errors) Every one of the **19,370,117 requests** of these runs was answered with status 200 or 201 : no error, no timeout. ## Memory What each part of the server held, in MB : at rest (the 60 seconds after API Maker and its sandboxes started, before any request) and under load. The bars show the second the whole server held the most memory while its database was loaded, out of the 7,941 MB of the server ; the table gives the most each part held on its own. API Maker is the resident memory of its process ; a container is counted the way `docker stats` counts it. API Maker · MongoDB of API Maker · Redis · PostgreSQL / MySQL · Sandboxes · Linux, Docker, the rest · Available MongoDB at rest under load PostgreSQL at rest under load MySQL at rest under load | Part | MongoDB
at rest → under load | PostgreSQL
at rest → under load | MySQL
at rest → under load | |---|--:|--:|--:| | **API Maker** (process), in RAM | 109 → **135** | 103 → **135** | 107 → **142** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | MongoDB of API Maker, in RAM | 125 → **290** | 276 → **276** | 275 → **276** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | Redis, in RAM | 3 → **4** | 3 → **4** | 3 → **4** | | Database under test, in RAM | MongoDB above | 38 → **211** | 421 → **507** | | … and in swap | MongoDB above | 0 → **0** | 0 → **0** | | Sandboxes (2 containers), in RAM | 55 → **602** | 55 → **545** | 55 → **520** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | **Whole server**, RAM used | 872 → **1593** | 1081 → **1761** | 1462 → **2048** | | Swap used | 0 → **0** | 0 → **0** | 0 → **0** | ## CPU On 4 vCPUs, API Maker, the database and the sandboxes share the same 4 vCPUs : every request costs the work of all of them. During *get all, public*, the CPU was split this way (average of the 15 seconds, in vCPUs : 4.0 is the whole server ; a process counts its own kernel time) : | | MongoDB | PostgreSQL | MySQL | |---|--:|--:|--:| | API Maker | 1.6 vCPU | 1.9 vCPU | 2.0 vCPU | | The database | 1.8 vCPU | 1.0 vCPU | 0.9 vCPU | | MongoDB of API Maker (when it is not the one tested) | – | 0.0 vCPU | 0.0 vCPU | | Sandboxes (idle : no code runs in get all) | 0.0 vCPU | 0.0 vCPU | 0.0 vCPU | | Whole server busy (of its 4 vCPUs) | 99 % | 90 % | 91 % | | … of which kernel time (network, disk), counted in the lines above too | 31 % | 35 % | 36 % | Steal time (CPU the hypervisor gave to other servers) was 0 % on average, 0 % at most. The load generator, sampled the same way, was never more than 21 % busy over its 16 cores : it was never the limit. ## Get all The schema API of a table answers all its rows : `GET /api/schema////
`. Every request reads the ten rows from the database, converts them with the schema of the table and sends them as JSON. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-api.html). ### Get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 7,423 119,615 requests in 15 s Latency p50 11ms average 12.0 ms Latency p99 28ms max 68 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,974** · 2 : **6,873** req/s · spread 14.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.6 vCPU**, **123 MB** RSS · MongoDB **1.8 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **99 %**, of which kernel (network, disk) **31 %** · memory used **902 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 8,395 127,345 requests in 15 s Latency p50 11ms average 11.3 ms Latency p99 14ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,489** · 2 : **8,300** req/s · spread 2.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.9 vCPU**, **115 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **90 %**, of which kernel (network, disk) **35 %** · memory used **1093 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 9,375 140,877 requests in 15 s Latency p50 10ms average 10.2 ms Latency p99 12ms max 23 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,393** · 2 : **9,358** req/s · spread 0.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.9 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **91 %**, of which kernel (network, disk) **36 %** · memory used **1472 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, public · round 1 of 2, the closer to the average ### Get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 7,021 102,801 requests in 15 s Latency p50 14ms average 14.1 ms Latency p99 28ms max 66 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,187** · 2 : **6,854** req/s · spread 4.7 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.9 vCPU**, **131 MB** RSS · MongoDB **1.5 vCPU** · sandboxes **0.0 vCPU**, **582 MB** · whole server busy **99 %**, of which kernel (network, disk) **29 %** · memory used **1576 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 7,680 117,913 requests in 15 s Latency p50 12ms average 12.2 ms Latency p99 15ms max 24 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,862** · 2 : **7,498** req/s · spread 4.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.1 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.9 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **91 %**, of which kernel (network, disk) **33 %** · memory used **1097 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 8,338 122,715 requests in 15 s Latency p50 12ms average 11.7 ms Latency p99 17ms max 25 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,181** · 2 : **8,494** req/s · spread 3.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.2 vCPU**, **121 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.8 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **93 %**, of which kernel (network, disk) **34 %** · memory used **1480 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, both tokens · round 1 of 2, the closer to the average ## Get all with caching The same request on a table whose API settings say `enableCaching: true`. The first answer is kept in Redis, under a key made of who asks and what is asked ; the next requests are answered from Redis until the answer expires or something writes the table. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get all with caching : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 26,115 399,054 requests in 15 s Latency p50 3ms average 3.3 ms Latency p99 5ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **26,609** · 2 : **25,621** req/s · spread 3.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **123 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **96 %**, of which kernel (network, disk) **31 %** · memory used **905 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 26,420 415,119 requests in 15 s Latency p50 3ms average 3.1 ms Latency p99 5ms max 14 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **27,674** · 2 : **25,166** req/s · spread 9.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **95 %**, of which kernel (network, disk) **32 %** · memory used **1087 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 25,630 382,667 requests in 15 s Latency p50 3ms average 3.4 ms Latency p99 6ms max 19 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **25,749** · 2 : **25,511** req/s · spread 0.9 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **129 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **518 MB** · Redis **0.2 vCPU** · whole server busy **95 %**, of which kernel (network, disk) **29 %** · memory used **2038 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, public · round 2 of 2, the closer to the average ### Get all with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 20,550 304,157 requests in 15 s Latency p50 4ms average 4.4 ms Latency p99 7ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **20,277** · 2 : **20,823** req/s · spread 2.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.5 vCPU**, **121 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.1 vCPU** · whole server busy **98 %**, of which kernel (network, disk) **27 %** · memory used **897 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 20,113 305,142 requests in 15 s Latency p50 4ms average 4.4 ms Latency p99 8ms max 18 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **20,341** · 2 : **19,885** req/s · spread 2.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.5 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.1 vCPU** · whole server busy **97 %**, of which kernel (network, disk) **26 %** · memory used **1087 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 20,763 322,649 requests in 15 s Latency p50 4ms average 4.2 ms Latency p99 7ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **21,511** · 2 : **20,016** req/s · spread 7.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.5 vCPU**, **119 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **97 %**, of which kernel (network, disk) **26 %** · memory used **1468 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, both tokens · round 1 of 2, the closer to the average ## Get all by stream `GET …/
/stream` : the rows are sent while they are read from the database cursor, so a large table never sits whole in memory. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-by-stream-api.html). ### Get all by stream : public No token : the API is public. Each answer : 2,477 bytes (MongoDB), status 200. **MongoDB** Requests / second 6,724 99,530 requests in 15 s Latency p50 14ms average 14.6 ms Latency p99 33ms max 76 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,636** · 2 : **6,812** req/s · spread 2.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.8 vCPU**, **128 MB** RSS · MongoDB **1.7 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **99 %**, of which kernel (network, disk) **29 %** · memory used **918 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 8,226 124,693 requests in 15 s Latency p50 12ms average 11.5 ms Latency p99 14ms max 24 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,313** · 2 : **8,138** req/s · spread 2.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **130 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **91 %**, of which kernel (network, disk) **34 %** · memory used **1102 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, public · round 1 of 2, the closer to the average **MySQL** Requests / second 8,355 120,464 requests in 15 s Latency p50 12ms average 11.9 ms Latency p99 14ms max 23 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,678** · 2 : **8,032** req/s · spread 7.7 % · the output below is round 2, the closer to the average (Server during this run) API Maker **2.2 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **518 MB** · whole server busy **91 %**, of which kernel (network, disk) **32 %** · memory used **2048 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, public · round 2 of 2, the closer to the average ### Get all by stream : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,577 bytes (MongoDB), status 200. **MongoDB** Requests / second 6,737 99,542 requests in 15 s Latency p50 14ms average 14.6 ms Latency p99 29ms max 64 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,838** · 2 : **6,637** req/s · spread 3 % · the output below is round 2, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **135 MB** RSS · MongoDB **1.5 vCPU** · sandboxes **0.0 vCPU**, **582 MB** · whole server busy **99 %**, of which kernel (network, disk) **26 %** · memory used **1593 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 7,486 113,375 requests in 15 s Latency p50 13ms average 12.7 ms Latency p99 15ms max 24 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,559** · 2 : **7,412** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.2 vCPU**, **129 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.9 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **93 %**, of which kernel (network, disk) **31 %** · memory used **1103 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 7,469 113,289 requests in 15 s Latency p50 13ms average 12.7 ms Latency p99 15ms max 24 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,553** · 2 : **7,386** req/s · spread 2.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.4 vCPU**, **134 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **94 %**, of which kernel (network, disk) **32 %** · memory used **1482 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, both tokens · round 1 of 2, the closer to the average ## Custom API calling get all A custom API written in TypeScript, `return await g.sys.db.getAll({ instance, database, collection })`. This code is *lean* : it only reads what it is handed and asks `g.sys` for a read, so API Maker runs it in the server itself, with QuickJS, on the thread which answers the request, and the request never leaves the server. Code which needs more (a package, the time of the machine, `g.shared`, …) runs in the sandbox of the account : see the next API. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API (public : customers_public ; both tokens : customers)** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` ### Custom API calling get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 5,178 75,384 requests in 15 s Latency p50 19ms average 19.4 ms Latency p99 34ms max 54 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,330** · 2 : **5,026** req/s · spread 5.9 % · the output below is round 2, the closer to the average (Server during this run) API Maker **2.3 vCPU**, **132 MB** RSS · MongoDB **1.2 vCPU** · sandboxes **0.0 vCPU**, **582 MB** · whole server busy **99 %**, of which kernel (network, disk) **23 %** · memory used **1571 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 5,658 85,337 requests in 15 s Latency p50 17ms average 17.1 ms Latency p99 20ms max 29 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,690** · 2 : **5,626** req/s · spread 1.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.7 vCPU**, **122 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **97 %**, of which kernel (network, disk) **25 %** · memory used **1099 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 6,016 90,945 requests in 15 s Latency p50 16ms average 16.0 ms Latency p99 19ms max 27 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,063** · 2 : **5,968** req/s · spread 1.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.7 vCPU**, **127 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **97 %**, of which kernel (network, disk) **26 %** · memory used **1478 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, public · round 1 of 2, the closer to the average ### Custom API calling get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,910 74,827 requests in 15 s Latency p50 19ms average 19.5 ms Latency p99 34ms max 50 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,989** · 2 : **4,831** req/s · spread 3.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.5 vCPU**, **130 MB** RSS · MongoDB **1.1 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **99 %**, of which kernel (network, disk) **21 %** · memory used **946 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 5,158 77,441 requests in 15 s Latency p50 19ms average 18.9 ms Latency p99 22ms max 30 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,163** · 2 : **5,153** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.8 vCPU**, **123 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **96 %**, of which kernel (network, disk) **23 %** · memory used **1100 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 5,536 83,494 requests in 15 s Latency p50 17ms average 17.5 ms Latency p99 20ms max 26 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,504** · 2 : **5,567** req/s · spread 1.1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **2.9 vCPU**, **131 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **518 MB** · whole server busy **98 %**, of which kernel (network, disk) **24 %** · memory used **2025 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, both tokens · round 2 of 2, the closer to the average ## Custom API in the sandbox The same custom API, with one line more : it reads `Date.now()`, the time of the machine, which lean code may not. So this code runs in a sandbox of the account (a container with Node.js 24) : the request goes from API Maker to a runner of the sandbox and back, and the rows are read from inside the sandbox by the core of API Maker loaded there. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API which runs in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const started = Date.now(); // the time of the machine : this code runs in the sandbox of the account return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,649 69,667 requests in 15 s Latency p50 20ms average 21.0 ms Latency p99 42ms max 112 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,645** · 2 : **4,653** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **125 MB** RSS · MongoDB **1.1 vCPU** · sandboxes **1.8 vCPU**, **577 MB** · whole server busy **100 %**, of which kernel (network, disk) **21 %** · memory used **1465 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api in the sandbox, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 5,126 77,048 requests in 15 s Latency p50 19ms average 19.0 ms Latency p99 35ms max 52 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,137** · 2 : **5,115** req/s · spread 0.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.1 vCPU**, **120 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.7 vCPU** · sandboxes **1.7 vCPU**, **538 MB** · whole server busy **99 %**, of which kernel (network, disk) **25 %** · memory used **1730 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api in the sandbox, public · round 1 of 2, the closer to the average **MySQL** Requests / second 5,486 82,434 requests in 15 s Latency p50 17ms average 17.7 ms Latency p99 33ms max 53 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,496** · 2 : **5,475** req/s · spread 0.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.2 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.6 vCPU** · sandboxes **1.7 vCPU**, **503 MB** · whole server busy **99 %**, of which kernel (network, disk) **27 %** · memory used **1991 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api in the sandbox, public · round 1 of 2, the closer to the average ## Get all with a pre hook Get all, with both tokens, on a table whose get all API has a pre hook written in TypeScript : before the API, the hook runs (lean code : in the server, with QuickJS), reads the signed-in person from `x-am-user-authorization` and keeps the rows of their country (`g.req.query.find`), the row scoping most applications need. Every row of the dataset is in India, as the person is, so the answer is the same ten rows. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html). **The pre hook of SCHEMA_GET_ALL on customers_pre_hook** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { if (!g.req.isApiRequestFromUser) return; const person = g.req.auth.authAMDB; // the person, from x-am-user-authorization if (!person) throw [{ code: T.EStatusCode.UNAUTHORIZED, message: 'Sign in first.' }]; const find = g.req.query.find ? (typeof g.req.query.find === 'string' ? JSON.parse(g.req.query.find) : g.req.query.find) : {}; g.req.query.find = { $and: [find, { country: person.country }] }; } module.exports = main; ``` With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 5,327 80,031 requests in 15 s Latency p50 18ms average 18.2 ms Latency p99 34ms max 66 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,336** · 2 : **5,318** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.1 vCPU**, **128 MB** RSS · MongoDB **1.4 vCPU** · sandboxes **0.0 vCPU**, **601 MB** · whole server busy **99 %**, of which kernel (network, disk) **24 %** · memory used **1507 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 6,151 93,295 requests in 15 s Latency p50 16ms average 15.6 ms Latency p99 18ms max 25 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,220** · 2 : **6,082** req/s · spread 2.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.4 vCPU**, **121 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.8 vCPU** · sandboxes **0.0 vCPU**, **545 MB** · whole server busy **95 %**, of which kernel (network, disk) **27 %** · memory used **1737 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 6,768 104,649 requests in 15 s Latency p50 14ms average 13.8 ms Latency p99 17ms max 29 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,977** · 2 : **6,559** req/s · spread 6.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.5 vCPU**, **126 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **503 MB** · whole server busy **95 %**, of which kernel (network, disk) **27 %** · memory used **1985 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average ## Get by id One row by its primary key : `GET …/
/get-by-id/`. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-by-id-api.html). ### Get by id : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 8,076 120,738 requests in 15 s Latency p50 11ms average 11.9 ms Latency p99 26ms max 79 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,104** · 2 : **8,049** req/s · spread 0.7 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.8 vCPU**, **131 MB** RSS · MongoDB **1.6 vCPU** · sandboxes **0.0 vCPU**, **477 MB** · whole server busy **99 %**, of which kernel (network, disk) **30 %** · memory used **1456 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 9,446 145,024 requests in 15 s Latency p50 10ms average 9.8 ms Latency p99 12ms max 22 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,669** · 2 : **9,222** req/s · spread 4.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.8 vCPU**, **122 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.1 vCPU** · sandboxes **0.0 vCPU**, **545 MB** · whole server busy **90 %**, of which kernel (network, disk) **35 %** · memory used **1728 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, public · round 1 of 2, the closer to the average **MySQL** Requests / second 9,893 153,601 requests in 15 s Latency p50 9ms average 9.3 ms Latency p99 11ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **10,240** · 2 : **9,545** req/s · spread 7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **127 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.9 vCPU** · sandboxes **0.0 vCPU**, **502 MB** · whole server busy **90 %**, of which kernel (network, disk) **35 %** · memory used **1982 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, public · round 1 of 2, the closer to the average ### Get by id : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 7,513 114,593 requests in 15 s Latency p50 12ms average 12.6 ms Latency p99 23ms max 46 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,640** · 2 : **7,386** req/s · spread 3.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.1 vCPU**, **130 MB** RSS · MongoDB **1.3 vCPU** · sandboxes **0.0 vCPU**, **477 MB** · whole server busy **99 %**, of which kernel (network, disk) **28 %** · memory used **1378 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 8,233 123,892 requests in 15 s Latency p50 11ms average 11.6 ms Latency p99 17ms max 25 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,260** · 2 : **8,206** req/s · spread 0.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.9 vCPU**, **122 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.0 vCPU** · sandboxes **0.0 vCPU**, **445 MB** · whole server busy **92 %**, of which kernel (network, disk) **33 %** · memory used **1643 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 8,892 137,132 requests in 15 s Latency p50 10ms average 10.4 ms Latency p99 13ms max 24 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,142** · 2 : **8,641** req/s · spread 5.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.2 vCPU**, **127 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.8 vCPU** · sandboxes **0.0 vCPU**, **502 MB** · whole server busy **92 %**, of which kernel (network, disk) **33 %** · memory used **1982 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, both tokens · round 1 of 2, the closer to the average ## Get by id with caching One row by its primary key, on a table with `enableCaching: true` : answered from Redis after the first request. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get by id with caching : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 26,444 400,693 requests in 15 s Latency p50 3ms average 3.2 ms Latency p99 5ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **26,714** · 2 : **26,174** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **126 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **477 MB** · Redis **0.2 vCPU** · whole server busy **95 %**, of which kernel (network, disk) **26 %** · memory used **1377 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 26,617 399,693 requests in 15 s Latency p50 3ms average 3.3 ms Latency p99 5ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **26,651** · 2 : **26,582** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **121 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **445 MB** · Redis **0.2 vCPU** · whole server busy **95 %**, of which kernel (network, disk) **28 %** · memory used **1642 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 27,185 416,448 requests in 15 s Latency p50 3ms average 3.1 ms Latency p99 5ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **27,764** · 2 : **26,606** req/s · spread 4.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **502 MB** · Redis **0.2 vCPU** · whole server busy **95 %**, of which kernel (network, disk) **26 %** · memory used **1984 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, public · round 1 of 2, the closer to the average ### Get by id with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 20,887 313,831 requests in 15 s Latency p50 4ms average 4.3 ms Latency p99 7ms max 18 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **20,852** · 2 : **20,922** req/s · spread 0.3 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.5 vCPU**, **127 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **477 MB** · Redis **0.1 vCPU** · whole server busy **97 %**, of which kernel (network, disk) **22 %** · memory used **1484 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 21,238 316,378 requests in 15 s Latency p50 4ms average 4.2 ms Latency p99 7ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **21,093** · 2 : **21,383** req/s · spread 1.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.5 vCPU**, **120 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **445 MB** · Redis **0.1 vCPU** · whole server busy **97 %**, of which kernel (network, disk) **23 %** · memory used **1644 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 22,684 345,677 requests in 15 s Latency p50 4ms average 3.8 ms Latency p99 6ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **23,046** · 2 : **22,322** req/s · spread 3.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.5 vCPU**, **126 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **502 MB** · Redis **0.1 vCPU** · whole server busy **97 %**, of which kernel (network, disk) **23 %** · memory used **1984 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, both tokens · round 1 of 2, the closer to the average ## Insert one row `POST …/
/save-single-or-multiple` with one row of 9 columns in the body : the schema checks and converts it, the database writes it, and the saved row is answered. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html). No token : the API is public. Each answer : 277 bytes (MongoDB), status 201. **MongoDB** Requests / second 3,198 47,640 requests in 15 s Latency p50 30ms average 31.0 ms Latency p99 63ms max 143 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,177** · 2 : **3,219** req/s · spread 1.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **130 MB** RSS · MongoDB **2.1 vCPU** · sandboxes **0.0 vCPU**, **476 MB** · whole server busy **96 %**, of which kernel (network, disk) **28 %** · memory used **1412 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · insert one row, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,969 60,055 requests in 15 s Latency p50 24ms average 24.5 ms Latency p99 28ms max 34 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,004** · 2 : **3,935** req/s · spread 1.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.5 vCPU**, **123 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.4 vCPU** · sandboxes **0.0 vCPU**, **444 MB** · whole server busy **91 %**, of which kernel (network, disk) **32 %** · memory used **1646 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · insert one row, public · round 1 of 2, the closer to the average **MySQL** Requests / second 3,181 47,899 requests in 15 s Latency p50 31ms average 30.8 ms Latency p99 35ms max 40 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,194** · 2 : **3,168** req/s · spread 0.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **128 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.2 vCPU** · sandboxes **0.0 vCPU**, **502 MB** · whole server busy **84 %**, of which kernel (network, disk) **33 %** · memory used **1989 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · insert one row, public · round 1 of 2, the closer to the average ## Custom API without a database A public custom API whose code returns a small object and reads no database : what running code of the account costs, without a database. Lean code runs in the server itself, with QuickJS ; the same code with `Date.now()` in it runs in a sandbox of the account : the trip from API Maker to the runner in its container and back. **In the server (lean code)** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from API Maker', time: 1 }; } module.exports = main; ``` Requests / second 26,046 394,004 requests in 15 s Latency p50 3ms average 3.3 ms Latency p99 6ms max 16 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **26,268** · 2 : **25,824** req/s · spread 1.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.9 vCPU**, **123 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **601 MB** · whole server busy **99 %**, of which kernel (network, disk) **23 %** · memory used **1578 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the server (lean code) · round 1 of 2, the closer to the average **In the sandbox** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from the sandbox', time: Date.now() }; } module.exports = main; ``` Requests / second 17,702 265,205 requests in 15 s Latency p50 5ms average 5.2 ms Latency p99 10ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **17,723** · 2 : **17,681** req/s · spread 0.2 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.0 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.9 vCPU**, **600 MB** · whole server busy **98 %**, of which kernel (network, disk) **21 %** · memory used **1594 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the sandbox · round 2 of 2, the closer to the average ## More connections *Get all, public* and *Get by id with caching, public* on MongoDB, one run of 15 seconds for each number of connections. More clients at once wait longer for their answer, and the server keeps answering them all. ### Get all, public, by connections **Get all, public, MongoDB : requests per second by connections** 10 connectionsp50 1 ms · p99 3 ms · 5,580 50 connectionsp50 6 ms · p99 16 ms · 6,813 100 connectionsp50 14 ms · p99 34 ms · 6,814 250 connectionsp50 35 ms · p99 56 ms · 6,952 500 connectionsp50 76 ms · p99 95 ms · 6,538 1,000 connectionsp50 152 ms · p99 174 ms · 6,525 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **5,580** | 1 ms | 3 ms | 8 ms | 0 | 87 % | 123 MB | | 50 | **6,813** | 6 ms | 16 ms | 34 ms | 0 | 98 % | 126 MB | | 100 | **6,814** | 14 ms | 34 ms | 84 ms | 0 | 99 % | 131 MB | | 250 | **6,952** | 35 ms | 56 ms | 96 ms | 0 | 99 % | 144 MB | | 500 | **6,538** | 76 ms | 95 ms | 141 ms | 0 | 99 % | 157 MB | | 1,000 | **6,525** | 152 ms | 174 ms | 224 ms | 0 | 99 % | 196 MB | ### Get by id with caching, public, by connections **Get by id with caching, public, MongoDB : requests per second by connections** 10 connectionsp50 0 ms · p99 1 ms · 11,584 50 connectionsp50 1 ms · p99 3 ms · 24,945 100 connectionsp50 3 ms · p99 5 ms · 28,147 250 connectionsp50 8 ms · p99 12 ms · 30,600 500 connectionsp50 16 ms · p99 22 ms · 29,908 1,000 connectionsp50 36 ms · p99 46 ms · 27,033 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **11,584** | 0 ms | 1 ms | 6 ms | 0 | 68 % | 131 MB | | 50 | **24,945** | 1 ms | 3 ms | 10 ms | 0 | 91 % | 131 MB | | 100 | **28,147** | 3 ms | 5 ms | 15 ms | 0 | 95 % | 134 MB | | 250 | **30,600** | 8 ms | 12 ms | 31 ms | 0 | 97 % | 143 MB | | 500 | **29,908** | 16 ms | 22 ms | 49 ms | 0 | 97 % | 157 MB | | 1,000 | **27,033** | 36 ms | 46 ms | 101 ms | 0 | 97 % | 184 MB | ## Questions ### How many requests per second can API Maker serve on 4 shared vCPUs ? On this 8 GB server, with the database on the same machine : 7,423 requests per second for a whole table of ten rows on MongoDB (PostgreSQL 8,395 · MySQL 9,375), 8,076 for one row by its id, and 26,444 when the answer is cached in Redis. A custom API in TypeScript which reads the table answers 5,178 requests per second when API Maker runs it itself (lean code), 4,649 when it runs in the sandbox of the account. ### How much memory does API Maker use ? The API Maker process held 109 MB at rest and 142 MB at most under load on this server, in RAM. The rest of the memory went to the databases (MongoDB, Redis, PostgreSQL or MySQL), the sandboxes which run the code of the account, and Linux itself. ### Do the two tokens slow the APIs down ? API Maker checks both tokens (x-am-authorization and x-am-user-authorization) and the groups of the API user on every request. Get all with both tokens answered 7,021 requests per second on MongoDB (public : 7,423), 7,680 requests per second on PostgreSQL (public : 8,395), 8,338 requests per second on MySQL (public : 9,375). The checks show most where the database does no work : a cached get all answered 20,550 requests per second with both tokens against 26,115 public on MongoDB. ### What does a pre hook cost ? A pre hook runs code of the account before the API ; a lean hook like this one runs in the server itself, with QuickJS. Get all with a row scoping pre hook answered 5,327 requests per second on MongoDB, against 7,021 for the same API without the hook. On 4 vCPUs, the API, the hook and the database share the same 4 vCPUs. ### Can I run these benchmarks myself ? Yes : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html) gives the dataset, the settings of every API and the exact autocannon commands. --- # API Maker benchmark : 8 vCPU, 32 GB RAM (Linode shared CPU) > API Maker on 8 shared vCPUs, 32 GB (Linode) : 11,002 req/s get all, 44,564 cached, on MongoDB, PostgreSQL and MySQL, with memory and autocannon output. Source: https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html Benchmark · Linode (Akamai Cloud) · Shared CPU · 12 October 2026 **8 vCPU, 32 GB RAM : 11,002 to 13,816 requests per second for a whole table.** API Maker 4.0.0 on a Linode 32 GB (g6-standard-8) : 8 shared vCPUs and 32 GB of RAM at $192 a month, its databases on the same machine. Every API was loaded for 15 seconds by autocannon from a second server, two times, on MongoDB, PostgreSQL and MySQL, public and with two tokens, while the server sampled the memory and CPU of every part each second. Get all · MongoDB 11,002req/s PostgreSQL 13,054 · MySQL 13,816 Get by id, cached 44,564req/s answered from Redis · PostgreSQL 43,050 · MySQL 43,160 Custom API · MongoDB 8,062req/s TypeScript, lean : run in the server · in the sandbox 7,636 API Maker memory 112MB at rest · 154 MB at most under load ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Linode 32 GB (g6-standard-8), shared cpu, $192 / month | | CPU | AMD EPYC 7642 48-Core Processor, 8 shared vCPUs (KVM)
KVM guest, 1 thread per core · L1d 512 KiB (8 instances) · L2 4 MiB (8 instances) · L3 128 MiB (8 instances) · BogoMIPS 4600.00 | | Memory | 32 GB (32,095 MB usable), swap 8.5 GB (496 MB of Linode + 8 GB made by the installer) | | Disk, region | 640 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 864bb64 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer (lean code of the account runs in the server with QuickJS : sandbox.codeInServer), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) · PostgreSQL 18.6 (official image postgres:18, max_connections 500) · MySQL 8.4.11 (official image mysql:8.4, max_connections 500) : all on the same server | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 403 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default), each opening up to 8 runners when it is busy (one per vCPU) | | Load generator | Dedicated 64 GB (g6-dedicated-32) : AMD EPYC 7642 48-Core Processor, 32 dedicated vCPUs, Ubuntu 24.04.4 LTS, Node.js 24.21.0, autocannon 8.0.0 with 20 worker threads | | Network | Private network of the same data centre, round trip 0.37 ms (ping) | | Host | A strict anti-affinity placement group kept the three shared CPU servers (2, 4 and 8 vCPUs) on three different hosts. All seven servers were measured at the same time, each by a load generator of its own. | | Date | 12 October 2026, 05:30 to 06:44 UTC | Only what a database needs was running while it was measured : API Maker and its two sandboxes, its MongoDB and Redis (API Maker always needs them) and the database under test. The other benchmark databases were stopped, API Maker was restarted and the swap emptied back into memory before each database, when it fitted there. How every number was taken : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/summary.html). ## The data Every table holds the ten rows of the [API Maker benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) : `https://apimaker.dev/json/benchmark_dataset.json`. Ten customers, ten columns each ; a *get all* answers all ten (2,418 bytes of JSON on MongoDB), a *get by id* one of them. | `_id` | `customer_id` | `first_name` | `last_name` | `phone` | `last_update` | `pincode` | `shipping_id` | `dob` | `country` | |---|---|---|---|---|---|---|---|---|---| | 60ae2488c37cd955cc144161 | 2 | NICK | WAHLBERG | 1123456789 | 2006-02-15T04:34:00.330Z | 111111 | 2 | 2022-10-30T03:25:03.000Z | India | | 60ae24c8c37cd955cc144162 | 1 | PENELOPE | GUINESS | 123456789 | 2006-02-15T04:34:00.330Z | 100050 | 1 | 2022-10-30T03:25:03.000Z | India | | 60ae247ac37cd955cc144160 | 3 | ED | CHASE | 2123456789 | 2006-02-15T04:34:00.330Z | 222222 | 3 | 2022-10-30T03:25:03.000Z | India | | 60ace1401efc56684403c68c | 4 | JENNIFER | DAVIS | 3123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 60accda51efc56684403c685 | 5 | JOHNNY | LOLLOBRIGIDA | 4123456789 | 2006-02-15T04:34:00.330Z | 485125 | 1 | 2022-10-30T03:25:03.000Z | India | | 606b7d364bebce00196eade7 | 6 | JOHNNY | LOLLOBRIGIDA | 5123456789 | 2006-02-15T04:34:00.330Z | 123456 | 2 | 2022-10-30T03:25:03.000Z | India | | 606b75961055000018fa9d98 | 7 | GRACE | MOSTEL | 6123456789 | 2006-02-15T04:34:00.330Z | 356589 | 3 | 2022-10-30T03:25:03.000Z | India | | 6064dd02730026001956663e | 8 | MATTHEW | JOHANSSON | 7123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 6064dcb8730026001956663c | 9 | JOE | SWANK | 8123456789 | 2006-02-15T04:34:00.330Z | 251415 | 1 | 2022-10-30T03:25:03.000Z | India | | 6064c4c02bafb90018955299 | 10 | CHRISTIAN | GABLE | 9123456789 | 2006-02-15T04:34:00.330Z | 100050 | | 2022-10-30T03:25:03.000Z | India | ## Results at a glance Requests per second, the average of two rounds of 15 seconds with 100 connections. *Public* APIs need no token ; *both tokens* means every request carries `x-am-authorization` (the token of an API user, whose groups decide what it may call) and `x-am-user-authorization` (the token of a row of the `customers` table, made by a DB token generator), and API Maker checks both. **Requests per second · 8 vCPU, 32 GB RAM, shared CPU** · MongoDB · PostgreSQL · MySQL Get allpublic · 11,002 · 13,054 · 13,816 Get allboth tokens · 11,882 · 12,013 · 12,645 Get all with cachingpublic · 41,093 · 39,947 · 40,335 Get all with cachingboth tokens · 34,364 · 32,966 · 33,000 Get all by streampublic · 10,646 · 12,914 · 12,489 Get all by streamboth tokens · 11,025 · 12,049 · 11,587 Custom API calling get all QuickJS · public · 8,062 · 9,350 · 9,698 Custom API calling get all QuickJS · both tokens · 8,393 · 8,433 · 8,962 Custom API in the sandbox Sandbox · public · 7,636 · 8,682 · 9,181 Get all with a pre hook QuickJS · both tokens · 8,512 · 9,668 · 10,192 Get by idpublic · 12,297 · 13,656 · 14,402 Get by idboth tokens · 12,654 · 12,548 · 13,222 Get by id with cachingpublic · 44,564 · 43,050 · 43,160 Get by id with cachingboth tokens · 36,219 · 34,322 · 34,667 Insert one rowpublic · 4,620 · 5,754 · 3,532 | API | Access | MongoDB | PostgreSQL | MySQL | |---|---|--:|--:|--:| | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all) | Public | **11,002** p99 20 ms | **13,054** p99 9 ms | **13,816** p99 8 ms | | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all) | Both tokens | **11,882** p99 17 ms | **12,013** p99 10 ms | **12,645** p99 10 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-caching) | Public | **41,093** p99 3 ms | **39,947** p99 3 ms | **40,335** p99 3 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-caching) | Both tokens | **34,364** p99 4 ms | **32,966** p99 4 ms | **33,000** p99 4 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-by-stream) | Public | **10,646** p99 21 ms | **12,914** p99 9 ms | **12,489** p99 10 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-by-stream) | Both tokens | **11,025** p99 18 ms | **12,049** p99 10 ms | **11,587** p99 10 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-calling-get-all) QuickJS | Public | **8,062** p99 23 ms | **9,350** p99 13 ms | **9,698** p99 12 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-calling-get-all) QuickJS | Both tokens | **8,393** p99 21 ms | **8,433** p99 14 ms | **8,962** p99 14 ms | | [Custom API in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-in-the-sandbox) Sandbox | Public | **7,636** p99 28 ms | **8,682** p99 20 ms | **9,181** p99 19 ms | | [Get all with a pre hook](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-all-with-a-pre-hook) QuickJS | Both tokens | **8,512** p99 24 ms | **9,668** p99 12 ms | **10,192** p99 13 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id) | Public | **12,297** p99 18 ms | **13,656** p99 8 ms | **14,402** p99 8 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id) | Both tokens | **12,654** p99 15 ms | **12,548** p99 10 ms | **13,222** p99 9 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id-with-caching) | Public | **44,564** p99 3 ms | **43,050** p99 3 ms | **43,160** p99 3 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#get-by-id-with-caching) | Both tokens | **36,219** p99 4 ms | **34,322** p99 4 ms | **34,667** p99 4 ms | | [Insert one row](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#insert-one-row) | Public | **4,620** p99 38 ms | **5,754** p99 19 ms | **3,532** p99 35 ms | | [Custom API without a database](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-without-a-database) | Public | **47,967** p99 3 ms | | | | [Custom API without a database, in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html#custom-api-without-a-database) | Public | **27,302** p99 8 ms | | | (0 errors) Every one of the **30,678,581 requests** of these runs was answered with status 200 or 201 : no error, no timeout. ## Memory What each part of the server held, in MB : at rest (the 60 seconds after API Maker and its sandboxes started, before any request) and under load. The bars show the second the whole server held the most memory while its database was loaded, out of the 32,095 MB of the server ; the table gives the most each part held on its own. API Maker is the resident memory of its process ; a container is counted the way `docker stats` counts it. API Maker · MongoDB of API Maker · Redis · PostgreSQL / MySQL · Sandboxes · Linux, Docker, the rest · Available MongoDB at rest under load PostgreSQL at rest under load MySQL at rest under load | Part | MongoDB
at rest → under load | PostgreSQL
at rest → under load | MySQL
at rest → under load | |---|--:|--:|--:| | **API Maker** (process), in RAM | 112 → **154** | 108 → **151** | 110 → **152** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | MongoDB of API Maker, in RAM | 127 → **352** | 334 → **336** | 334 → **336** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | Redis, in RAM | 3 → **4** | 3 → **4** | 3 → **4** | | Database under test, in RAM | MongoDB above | 39 → **300** | 421 → **516** | | … and in swap | MongoDB above | 0 → **0** | 0 → **0** | | Sandboxes (2 containers), in RAM | 55 → **849** | 55 → **894** | 55 → **875** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | **Whole server**, RAM used | 1102 → **2162** | 1341 → **2508** | 1741 → **2710** | | Swap used | 0 → **0** | 0 → **0** | 0 → **0** | ## CPU On 8 vCPUs, API Maker, the database and the sandboxes share the same 8 vCPUs : every request costs the work of all of them. During *get all, public*, the CPU was split this way (average of the 15 seconds, in vCPUs : 8.0 is the whole server ; a process counts its own kernel time) : | | MongoDB | PostgreSQL | MySQL | |---|--:|--:|--:| | API Maker | 2.8 vCPU | 3.3 vCPU | 3.4 vCPU | | The database | 4.1 vCPU | 1.6 vCPU | 1.5 vCPU | | MongoDB of API Maker (when it is not the one tested) | – | 0.0 vCPU | 0.0 vCPU | | Sandboxes (idle : no code runs in get all) | 0.0 vCPU | 0.0 vCPU | 0.0 vCPU | | Whole server busy (of its 8 vCPUs) | 98 % | 78 % | 78 % | | … of which kernel time (network, disk), counted in the lines above too | 33 % | 29 % | 30 % | Steal time (CPU the hypervisor gave to other servers) was 0 % on average, 0 % at most. The load generator, sampled the same way, was never more than 12 % busy over its 32 cores : it was never the limit. ## Get all The schema API of a table answers all its rows : `GET /api/schema////
`. Every request reads the ten rows from the database, converts them with the schema of the table and sends them as JSON. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-api.html). ### Get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 11,002 173,721 requests in 15 s Latency p50 8ms average 8.1 ms Latency p99 20ms max 51 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **11,582** · 2 : **10,423** req/s · spread 10.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.8 vCPU**, **132 MB** RSS · MongoDB **4.1 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **98 %**, of which kernel (network, disk) **33 %** · memory used **1108 MB** of 32095 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 13,054 201,063 requests in 15 s Latency p50 7ms average 7.0 ms Latency p99 9ms max 13 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,405** · 2 : **12,703** req/s · spread 5.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **124 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.6 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **78 %**, of which kernel (network, disk) **29 %** · memory used **1379 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 13,816 215,068 requests in 15 s Latency p50 6ms average 6.5 ms Latency p99 8ms max 13 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **14,339** · 2 : **13,294** req/s · spread 7.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.5 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **78 %**, of which kernel (network, disk) **30 %** · memory used **1760 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, public · round 1 of 2, the closer to the average ### Get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 11,882 187,751 requests in 15 s Latency p50 7ms average 7.5 ms Latency p99 17ms max 43 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,518** · 2 : **11,246** req/s · spread 10.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.6 vCPU**, **132 MB** RSS · MongoDB **3.1 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **96 %**, of which kernel (network, disk) **29 %** · memory used **1127 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 12,013 178,911 requests in 15 s Latency p50 8ms average 7.9 ms Latency p99 10ms max 16 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,098** · 2 : **11,928** req/s · spread 1.4 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.8 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.4 vCPU** · sandboxes **0.0 vCPU**, **890 MB** · whole server busy **80 %**, of which kernel (network, disk) **27 %** · memory used **2444 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 12,645 187,770 requests in 15 s Latency p50 7ms average 7.5 ms Latency p99 10ms max 14 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,773** · 2 : **12,518** req/s · spread 2 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.9 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.3 vCPU** · sandboxes **0.0 vCPU**, **874 MB** · whole server busy **82 %**, of which kernel (network, disk) **28 %** · memory used **2649 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, both tokens · round 2 of 2, the closer to the average ## Get all with caching The same request on a table whose API settings say `enableCaching: true`. The first answer is kept in Redis, under a key made of who asks and what is asked ; the next requests are answered from Redis until the answer expires or something writes the table. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get all with caching : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 41,093 634,592 requests in 15 s Latency p50 2ms average 1.9 ms Latency p99 3ms max 9 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **42,307** · 2 : **39,880** req/s · spread 5.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.2 vCPU**, **129 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **85 %**, of which kernel (network, disk) **27 %** · memory used **1108 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 39,947 601,568 requests in 15 s Latency p50 2ms average 2.0 ms Latency p99 3ms max 9 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **40,101** · 2 : **39,792** req/s · spread 0.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.2 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **86 %**, of which kernel (network, disk) **26 %** · memory used **1349 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 40,335 605,248 requests in 15 s Latency p50 2ms average 2.0 ms Latency p99 3ms max 12 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **40,351** · 2 : **40,319** req/s · spread 0.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.2 vCPU**, **126 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **57 MB** · Redis **0.2 vCPU** · whole server busy **86 %**, of which kernel (network, disk) **26 %** · memory used **1731 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, public · round 1 of 2, the closer to the average ### Get all with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 34,364 511,751 requests in 15 s Latency p50 2ms average 2.4 ms Latency p99 4ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **34,113** · 2 : **34,614** req/s · spread 1.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.6 vCPU**, **128 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **89 %**, of which kernel (network, disk) **23 %** · memory used **1110 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 32,966 491,200 requests in 15 s Latency p50 3ms average 2.5 ms Latency p99 4ms max 10 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **32,746** · 2 : **33,186** req/s · spread 1.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.6 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **89 %**, of which kernel (network, disk) **22 %** · memory used **1350 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 33,000 494,611 requests in 15 s Latency p50 3ms average 2.5 ms Latency p99 4ms max 11 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **32,973** · 2 : **33,027** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.6 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **57 MB** · Redis **0.2 vCPU** · whole server busy **89 %**, of which kernel (network, disk) **22 %** · memory used **1743 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, both tokens · round 1 of 2, the closer to the average ## Get all by stream `GET …/
/stream` : the rows are sent while they are read from the database cursor, so a large table never sits whole in memory. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-by-stream-api.html). ### Get all by stream : public No token : the API is public. Each answer : 2,477 bytes (MongoDB), status 200. **MongoDB** Requests / second 10,646 160,081 requests in 15 s Latency p50 8ms average 8.9 ms Latency p99 21ms max 44 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **10,673** · 2 : **10,620** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.1 vCPU**, **145 MB** RSS · MongoDB **3.8 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **98 %**, of which kernel (network, disk) **30 %** · memory used **1128 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 12,914 191,785 requests in 15 s Latency p50 7ms average 7.3 ms Latency p99 9ms max 14 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,042** · 2 : **12,785** req/s · spread 2 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.5 vCPU**, **143 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.5 vCPU** · sandboxes **0.0 vCPU**, **890 MB** · whole server busy **79 %**, of which kernel (network, disk) **28 %** · memory used **2483 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, public · round 2 of 2, the closer to the average **MySQL** Requests / second 12,489 185,952 requests in 15 s Latency p50 8ms average 7.6 ms Latency p99 10ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,580** · 2 : **12,398** req/s · spread 1.5 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.9 vCPU**, **151 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.2 vCPU** · sandboxes **0.0 vCPU**, **874 MB** · whole server busy **81 %**, of which kernel (network, disk) **27 %** · memory used **2710 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, public · round 2 of 2, the closer to the average ### Get all by stream : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,577 bytes (MongoDB), status 200. **MongoDB** Requests / second 11,025 162,260 requests in 15 s Latency p50 8ms average 8.7 ms Latency p99 18ms max 41 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **11,232** · 2 : **10,818** req/s · spread 3.8 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.9 vCPU**, **150 MB** RSS · MongoDB **2.8 vCPU** · sandboxes **0.0 vCPU**, **848 MB** · whole server busy **96 %**, of which kernel (network, disk) **26 %** · memory used **2162 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 12,049 180,215 requests in 15 s Latency p50 8ms average 7.8 ms Latency p99 10ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,082** · 2 : **12,015** req/s · spread 0.6 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.8 vCPU**, **142 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.4 vCPU** · sandboxes **0.0 vCPU**, **890 MB** · whole server busy **80 %**, of which kernel (network, disk) **27 %** · memory used **2508 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 11,587 174,277 requests in 15 s Latency p50 8ms average 8.1 ms Latency p99 10ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **11,619** · 2 : **11,556** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.2 vCPU**, **142 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.2 vCPU** · sandboxes **0.0 vCPU**, **57 MB** · whole server busy **82 %**, of which kernel (network, disk) **26 %** · memory used **1779 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, both tokens · round 1 of 2, the closer to the average ## Custom API calling get all A custom API written in TypeScript, `return await g.sys.db.getAll({ instance, database, collection })`. This code is *lean* : it only reads what it is handed and asks `g.sys` for a read, so API Maker runs it in the server itself, with QuickJS, on the thread which answers the request, and the request never leaves the server. Code which needs more (a package, the time of the machine, `g.shared`, …) runs in the sandbox of the account : see the next API. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API (public : customers_public ; both tokens : customers)** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` ### Custom API calling get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 8,062 120,926 requests in 15 s Latency p50 12ms average 11.9 ms Latency p99 23ms max 39 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,062** · 2 : **8,062** req/s · spread 0 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.1 vCPU**, **141 MB** RSS · MongoDB **2.9 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **97 %**, of which kernel (network, disk) **25 %** · memory used **1171 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 9,350 138,597 requests in 15 s Latency p50 10ms average 10.3 ms Latency p99 13ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,240** · 2 : **9,460** req/s · spread 2.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.9 vCPU**, **139 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.2 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **88 %**, of which kernel (network, disk) **22 %** · memory used **1389 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 9,698 145,990 requests in 15 s Latency p50 10ms average 9.8 ms Latency p99 12ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,734** · 2 : **9,662** req/s · spread 0.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.9 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.0 vCPU** · sandboxes **0.0 vCPU**, **57 MB** · whole server busy **86 %**, of which kernel (network, disk) **22 %** · memory used **1780 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, public · round 1 of 2, the closer to the average ### Custom API calling get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 8,393 127,441 requests in 15 s Latency p50 11ms average 11.3 ms Latency p99 21ms max 34 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,496** · 2 : **8,290** req/s · spread 2.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.8 vCPU**, **142 MB** RSS · MongoDB **2.1 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **96 %**, of which kernel (network, disk) **21 %** · memory used **1177 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 8,433 126,032 requests in 15 s Latency p50 11ms average 11.4 ms Latency p99 14ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,464** · 2 : **8,402** req/s · spread 0.7 % · the output below is round 2, the closer to the average (Server during this run) API Maker **5.0 vCPU**, **139 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.0 vCPU** · sandboxes **0.0 vCPU**, **890 MB** · whole server busy **88 %**, of which kernel (network, disk) **21 %** · memory used **2499 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 8,962 133,707 requests in 15 s Latency p50 11ms average 10.7 ms Latency p99 14ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,914** · 2 : **9,010** req/s · spread 1.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **5.1 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.0 vCPU** · sandboxes **0.0 vCPU**, **57 MB** · whole server busy **88 %**, of which kernel (network, disk) **21 %** · memory used **1783 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, both tokens · round 1 of 2, the closer to the average ## Custom API in the sandbox The same custom API, with one line more : it reads `Date.now()`, the time of the machine, which lean code may not. So this code runs in a sandbox of the account (a container with Node.js 24) : the request goes from API Maker to a runner of the sandbox and back, and the rows are read from inside the sandbox by the core of API Maker loaded there. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API which runs in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const started = Date.now(); // the time of the machine : this code runs in the sandbox of the account return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 7,636 113,499 requests in 15 s Latency p50 12ms average 12.7 ms Latency p99 28ms max 64 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,567** · 2 : **7,705** req/s · spread 1.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.9 vCPU**, **136 MB** RSS · MongoDB **2.3 vCPU** · sandboxes **3.7 vCPU**, **826 MB** · whole server busy **99 %**, of which kernel (network, disk) **21 %** · memory used **1994 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api in the sandbox, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 8,682 130,504 requests in 15 s Latency p50 11ms average 11.0 ms Latency p99 20ms max 32 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,702** · 2 : **8,662** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.3 vCPU**, **133 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.1 vCPU** · sandboxes **3.6 vCPU**, **888 MB** · whole server busy **97 %**, of which kernel (network, disk) **26 %** · memory used **2459 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api in the sandbox, public · round 1 of 2, the closer to the average **MySQL** Requests / second 9,181 137,527 requests in 15 s Latency p50 10ms average 10.4 ms Latency p99 19ms max 32 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,169** · 2 : **9,194** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.4 vCPU**, **133 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.0 vCPU** · sandboxes **3.5 vCPU**, **858 MB** · whole server busy **96 %**, of which kernel (network, disk) **27 %** · memory used **2650 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api in the sandbox, public · round 1 of 2, the closer to the average ## Get all with a pre hook Get all, with both tokens, on a table whose get all API has a pre hook written in TypeScript : before the API, the hook runs (lean code : in the server, with QuickJS), reads the signed-in person from `x-am-user-authorization` and keeps the rows of their country (`g.req.query.find`), the row scoping most applications need. Every row of the dataset is in India, as the person is, so the answer is the same ten rows. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html). **The pre hook of SCHEMA_GET_ALL on customers_pre_hook** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { if (!g.req.isApiRequestFromUser) return; const person = g.req.auth.authAMDB; // the person, from x-am-user-authorization if (!person) throw [{ code: T.EStatusCode.UNAUTHORIZED, message: 'Sign in first.' }]; const find = g.req.query.find ? (typeof g.req.query.find === 'string' ? JSON.parse(g.req.query.find) : g.req.query.find) : {}; g.req.query.find = { $and: [find, { country: person.country }] }; } module.exports = main; ``` With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 8,512 129,576 requests in 15 s Latency p50 11ms average 11.1 ms Latency p99 24ms max 55 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,639** · 2 : **8,384** req/s · spread 3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.8 vCPU**, **140 MB** RSS · MongoDB **3.2 vCPU** · sandboxes **0.0 vCPU**, **831 MB** · whole server busy **97 %**, of which kernel (network, disk) **25 %** · memory used **2008 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 9,668 145,230 requests in 15 s Latency p50 10ms average 9.8 ms Latency p99 12ms max 21 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,682** · 2 : **9,654** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.4 vCPU**, **138 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.4 vCPU** · sandboxes **0.0 vCPU**, **893 MB** · whole server busy **84 %**, of which kernel (network, disk) **23 %** · memory used **2464 MB** of 32095 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 10,192 153,085 requests in 15 s Latency p50 9ms average 9.3 ms Latency p99 13ms max 22 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **10,208** · 2 : **10,177** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.4 vCPU**, **136 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.2 vCPU** · sandboxes **0.0 vCPU**, **858 MB** · whole server busy **84 %**, of which kernel (network, disk) **24 %** · memory used **2669 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average ## Get by id One row by its primary key : `GET …/
/get-by-id/`. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-by-id-api.html). ### Get by id : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 12,297 181,380 requests in 15 s Latency p50 7ms average 7.8 ms Latency p99 18ms max 48 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,502** · 2 : **12,093** req/s · spread 3.3 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.1 vCPU**, **142 MB** RSS · MongoDB **3.6 vCPU** · sandboxes **0.0 vCPU**, **832 MB** · whole server busy **97 %**, of which kernel (network, disk) **32 %** · memory used **2108 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 13,656 204,840 requests in 15 s Latency p50 7ms average 6.8 ms Latency p99 8ms max 13 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,657** · 2 : **13,655** req/s · spread 0 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.1 vCPU**, **138 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.7 vCPU** · sandboxes **0.0 vCPU**, **893 MB** · whole server busy **77 %**, of which kernel (network, disk) **28 %** · memory used **2456 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, public · round 1 of 2, the closer to the average **MySQL** Requests / second 14,402 214,485 requests in 15 s Latency p50 6ms average 6.5 ms Latency p99 8ms max 13 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **14,299** · 2 : **14,506** req/s · spread 1.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **135 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.4 vCPU** · sandboxes **0.0 vCPU**, **858 MB** · whole server busy **77 %**, of which kernel (network, disk) **29 %** · memory used **2670 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, public · round 1 of 2, the closer to the average ### Get by id : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 12,654 189,329 requests in 15 s Latency p50 7ms average 7.4 ms Latency p99 15ms max 29 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,622** · 2 : **12,686** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.9 vCPU**, **141 MB** RSS · MongoDB **2.6 vCPU** · sandboxes **0.0 vCPU**, **830 MB** · whole server busy **94 %**, of which kernel (network, disk) **27 %** · memory used **1969 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 12,548 189,333 requests in 15 s Latency p50 7ms average 7.4 ms Latency p99 10ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,623** · 2 : **12,472** req/s · spread 1.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **138 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.6 vCPU** · sandboxes **0.0 vCPU**, **893 MB** · whole server busy **79 %**, of which kernel (network, disk) **26 %** · memory used **2459 MB** of 32095 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 13,222 201,103 requests in 15 s Latency p50 7ms average 7.0 ms Latency p99 9ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,037** · 2 : **13,408** req/s · spread 2.8 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.8 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.3 vCPU** · sandboxes **0.0 vCPU**, **860 MB** · whole server busy **80 %**, of which kernel (network, disk) **27 %** · memory used **2677 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, both tokens · round 2 of 2, the closer to the average ## Get by id with caching One row by its primary key, on a table with `enableCaching: true` : answered from Redis after the first request. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get by id with caching : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 44,564 679,518 requests in 15 s Latency p50 2ms average 1.7 ms Latency p99 3ms max 10 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **45,302** · 2 : **43,826** req/s · spread 3.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.3 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **830 MB** · Redis **0.2 vCPU** · whole server busy **86 %**, of which kernel (network, disk) **23 %** · memory used **1967 MB** of 32095 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 43,050 656,296 requests in 15 s Latency p50 2ms average 1.8 ms Latency p99 3ms max 9 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **43,752** · 2 : **42,348** req/s · spread 3.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.2 vCPU**, **134 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **824 MB** · Redis **0.2 vCPU** · whole server busy **85 %**, of which kernel (network, disk) **23 %** · memory used **2415 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 43,160 644,159 requests in 15 s Latency p50 2ms average 1.8 ms Latency p99 3ms max 10 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **42,947** · 2 : **43,372** req/s · spread 1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.3 vCPU**, **134 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **858 MB** · Redis **0.2 vCPU** · whole server busy **85 %**, of which kernel (network, disk) **23 %** · memory used **2667 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, public · round 1 of 2, the closer to the average ### Get by id with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 36,219 531,520 requests in 15 s Latency p50 2ms average 2.3 ms Latency p99 4ms max 10 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **37,002** · 2 : **35,436** req/s · spread 4.3 % · the output below is round 2, the closer to the average (Server during this run) API Maker **6.6 vCPU**, **138 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **832 MB** · Redis **0.2 vCPU** · whole server busy **89 %**, of which kernel (network, disk) **20 %** · memory used **2141 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 34,322 506,698 requests in 15 s Latency p50 2ms average 2.5 ms Latency p99 4ms max 14 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **33,780** · 2 : **34,864** req/s · spread 3.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.6 vCPU**, **134 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **824 MB** · Redis **0.2 vCPU** · whole server busy **89 %**, of which kernel (network, disk) **18 %** · memory used **2393 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 34,667 515,725 requests in 15 s Latency p50 2ms average 2.4 ms Latency p99 4ms max 10 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **34,382** · 2 : **34,952** req/s · spread 1.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.6 vCPU**, **134 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **858 MB** · Redis **0.2 vCPU** · whole server busy **89 %**, of which kernel (network, disk) **20 %** · memory used **2652 MB** of 32095 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, both tokens · round 1 of 2, the closer to the average ## Insert one row `POST …/
/save-single-or-multiple` with one row of 9 columns in the body : the schema checks and converts it, the database writes it, and the saved row is answered. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html). No token : the API is public. Each answer : 277 bytes (MongoDB), status 201. **MongoDB** Requests / second 4,620 67,532 requests in 15 s Latency p50 21ms average 21.7 ms Latency p99 38ms max 62 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,737** · 2 : **4,503** req/s · spread 5.1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **2.1 vCPU**, **143 MB** RSS · MongoDB **4.2 vCPU** · sandboxes **0.0 vCPU**, **830 MB** · whole server busy **91 %**, of which kernel (network, disk) **27 %** · memory used **2124 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · MongoDB · insert one row, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 5,754 86,194 requests in 15 s Latency p50 17ms average 16.9 ms Latency p99 19ms max 35 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,747** · 2 : **5,761** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.3 vCPU**, **138 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **2.1 vCPU** · sandboxes **0.0 vCPU**, **823 MB** · whole server busy **72 %**, of which kernel (network, disk) **24 %** · memory used **2408 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · insert one row, public · round 1 of 2, the closer to the average **MySQL** Requests / second 3,532 53,217 requests in 15 s Latency p50 28ms average 27.7 ms Latency p99 35ms max 42 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,515** · 2 : **3,548** req/s · spread 1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.6 vCPU**, **139 MB** RSS · MongoDB **0.0 vCPU** · MySQL **3.2 vCPU** · sandboxes **0.0 vCPU**, **858 MB** · whole server busy **77 %**, of which kernel (network, disk) **21 %** · memory used **2653 MB** of 32095 MB · steal **0 %** · swap not touched autocannon · MySQL · insert one row, public · round 2 of 2, the closer to the average ## Custom API without a database A public custom API whose code returns a small object and reads no database : what running code of the account costs, without a database. Lean code runs in the server itself, with QuickJS ; the same code with `Date.now()` in it runs in a sandbox of the account : the trip from API Maker to the runner in its container and back. **In the server (lean code)** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from API Maker', time: 1 }; } module.exports = main; ``` Requests / second 47,967 708,272 requests in 15 s Latency p50 2ms average 1.6 ms Latency p99 3ms max 10 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **47,218** · 2 : **48,716** req/s · spread 3.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **7.7 vCPU**, **134 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **850 MB** · whole server busy **98 %**, of which kernel (network, disk) **22 %** · memory used **2123 MB** of 32095 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the server (lean code) · round 1 of 2, the closer to the average **In the sandbox** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from the sandbox', time: Date.now() }; } module.exports = main; ``` Requests / second 27,302 417,159 requests in 15 s Latency p50 3ms average 3.1 ms Latency p99 8ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **26,793** · 2 : **27,811** req/s · spread 3.7 % · the output below is round 2, the closer to the average (Server during this run) API Maker **5.3 vCPU**, **136 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **2.1 vCPU**, **850 MB** · whole server busy **94 %**, of which kernel (network, disk) **23 %** · memory used **2121 MB** of 32096 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the sandbox · round 2 of 2, the closer to the average ## More connections *Get all, public* and *Get by id with caching, public* on MongoDB, one run of 15 seconds for each number of connections. More clients at once wait longer for their answer, and the server keeps answering them all. ### Get all, public, by connections **Get all, public, MongoDB : requests per second by connections** 10 connectionsp50 1 ms · p99 2 ms · 7,548 50 connectionsp50 4 ms · p99 10 ms · 10,582 100 connectionsp50 8 ms · p99 21 ms · 10,818 250 connectionsp50 22 ms · p99 36 ms · 10,841 500 connectionsp50 47 ms · p99 61 ms · 10,378 1,000 connectionsp50 97 ms · p99 111 ms · 10,268 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **7,548** | 1 ms | 2 ms | 7 ms | 0 | 73 % | 134 MB | | 50 | **10,582** | 4 ms | 10 ms | 21 ms | 0 | 95 % | 137 MB | | 100 | **10,818** | 8 ms | 21 ms | 61 ms | 0 | 98 % | 142 MB | | 250 | **10,841** | 22 ms | 36 ms | 72 ms | 0 | 98 % | 155 MB | | 500 | **10,378** | 47 ms | 61 ms | 90 ms | 0 | 98 % | 170 MB | | 1,000 | **10,268** | 97 ms | 111 ms | 139 ms | 0 | 98 % | 203 MB | ### Get by id with caching, public, by connections **Get by id with caching, public, MongoDB : requests per second by connections** 10 connectionsp50 0 ms · p99 0 ms · 16,350 50 connectionsp50 1 ms · p99 2 ms · 38,344 100 connectionsp50 2 ms · p99 3 ms · 42,203 250 connectionsp50 5 ms · p99 9 ms · 44,362 500 connectionsp50 11 ms · p99 15 ms · 43,359 1,000 connectionsp50 22 ms · p99 26 ms · 45,183 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **16,350** | 0 ms | 0 ms | 4 ms | 0 | 55 % | 139 MB | | 50 | **38,344** | 1 ms | 2 ms | 6 ms | 0 | 85 % | 139 MB | | 100 | **42,203** | 2 ms | 3 ms | 10 ms | 0 | 85 % | 143 MB | | 250 | **44,362** | 5 ms | 9 ms | 27 ms | 0 | 87 % | 155 MB | | 500 | **43,359** | 11 ms | 15 ms | 34 ms | 0 | 87 % | 164 MB | | 1,000 | **45,183** | 22 ms | 26 ms | 52 ms | 0 | 87 % | 193 MB | ## Questions ### How many requests per second can API Maker serve on 8 shared vCPUs ? On this 32 GB server, with the database on the same machine : 11,002 requests per second for a whole table of ten rows on MongoDB (PostgreSQL 13,054 · MySQL 13,816), 12,297 for one row by its id, and 44,564 when the answer is cached in Redis. A custom API in TypeScript which reads the table answers 8,062 requests per second when API Maker runs it itself (lean code), 7,636 when it runs in the sandbox of the account. ### How much memory does API Maker use ? The API Maker process held 112 MB at rest and 154 MB at most under load on this server, in RAM. The rest of the memory went to the databases (MongoDB, Redis, PostgreSQL or MySQL), the sandboxes which run the code of the account, and Linux itself. ### Do the two tokens slow the APIs down ? API Maker checks both tokens (x-am-authorization and x-am-user-authorization) and the groups of the API user on every request. Get all with both tokens answered 11,882 requests per second on MongoDB (public : 11,002), 12,013 requests per second on PostgreSQL (public : 13,054), 12,645 requests per second on MySQL (public : 13,816). The checks show most where the database does no work : a cached get all answered 34,364 requests per second with both tokens against 41,093 public on MongoDB. ### What does a pre hook cost ? A pre hook runs code of the account before the API ; a lean hook like this one runs in the server itself, with QuickJS. Get all with a row scoping pre hook answered 8,512 requests per second on MongoDB, against 11,882 for the same API without the hook. On 8 vCPUs, the API, the hook and the database share the same 8 vCPUs. ### Can I run these benchmarks myself ? Yes : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html) gives the dataset, the settings of every API and the exact autocannon commands. --- # API Maker benchmark : 2 vCPU, 4 GB RAM (Linode dedicated CPU) > API Maker on 2 dedicated vCPUs, 4 GB (Linode) : 3,712 req/s get all, 16,455 cached, on MongoDB, PostgreSQL and MySQL, with memory and autocannon output. Source: https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html Benchmark · Linode (Akamai Cloud) · Dedicated CPU · 12 October 2026 **2 vCPU, 4 GB RAM : 3,712 to 5,418 requests per second for a whole table.** API Maker 4.0.0 on a Linode Dedicated 4 GB (g6-dedicated-2) : 2 dedicated vCPUs and 4 GB of RAM at $36 a month, its databases on the same machine. Every API was loaded for 15 seconds by autocannon from a second server, two times, on MongoDB, PostgreSQL and MySQL, public and with two tokens, while the server sampled the memory and CPU of every part each second. Get all · MongoDB 3,712req/s PostgreSQL 4,782 · MySQL 5,418 Get by id, cached 16,455req/s answered from Redis · PostgreSQL 16,517 · MySQL 16,379 Custom API · MongoDB 2,591req/s TypeScript, lean : run in the server · in the sandbox 2,269 API Maker memory 99MB at rest · 127 MB at most under load ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Dedicated 4 GB (g6-dedicated-2), dedicated cpu, $36 / month | | CPU | AMD EPYC 7642 48-Core Processor, 2 dedicated vCPUs (KVM)
KVM guest, 1 thread per core · L1d 128 KiB (2 instances) · L2 1 MiB (2 instances) · L3 32 MiB (2 instances) · BogoMIPS 4599.99 | | Memory | 4 GB (3,915 MB usable), swap 4.3 GB (496 MB of Linode + 3.8 GB made by the installer) | | Disk, region | 80 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 864bb64 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer (lean code of the account runs in the server with QuickJS : sandbox.codeInServer), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) · PostgreSQL 18.6 (official image postgres:18, max_connections 500) · MySQL 8.4.11 (official image mysql:8.4, max_connections 500) : all on the same server | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 403 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default), each opening up to 2 runners when it is busy (one per vCPU) | | Load generator | Dedicated 16 GB (g6-dedicated-8) : AMD EPYC 7642 48-Core Processor, 8 dedicated vCPUs, Ubuntu 24.04.4 LTS, Node.js 24.21.0, autocannon 8.0.0 with 5 worker threads | | Network | Private network of the same data centre, round trip 0.33 ms (ping) | | Host | A strict anti-affinity placement group kept the three dedicated CPU servers (2, 4 and 8 vCPUs) on three different hosts. All seven servers were measured at the same time, each by a load generator of its own. | | Date | 12 October 2026, 05:30 to 06:44 UTC | Only what a database needs was running while it was measured : API Maker and its two sandboxes, its MongoDB and Redis (API Maker always needs them) and the database under test. The other benchmark databases were stopped, API Maker was restarted and the swap emptied back into memory before each database, when it fitted there. How every number was taken : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/summary.html). ## The data Every table holds the ten rows of the [API Maker benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) : `https://apimaker.dev/json/benchmark_dataset.json`. Ten customers, ten columns each ; a *get all* answers all ten (2,418 bytes of JSON on MongoDB), a *get by id* one of them. | `_id` | `customer_id` | `first_name` | `last_name` | `phone` | `last_update` | `pincode` | `shipping_id` | `dob` | `country` | |---|---|---|---|---|---|---|---|---|---| | 60ae2488c37cd955cc144161 | 2 | NICK | WAHLBERG | 1123456789 | 2006-02-15T04:34:00.330Z | 111111 | 2 | 2022-10-30T03:25:03.000Z | India | | 60ae24c8c37cd955cc144162 | 1 | PENELOPE | GUINESS | 123456789 | 2006-02-15T04:34:00.330Z | 100050 | 1 | 2022-10-30T03:25:03.000Z | India | | 60ae247ac37cd955cc144160 | 3 | ED | CHASE | 2123456789 | 2006-02-15T04:34:00.330Z | 222222 | 3 | 2022-10-30T03:25:03.000Z | India | | 60ace1401efc56684403c68c | 4 | JENNIFER | DAVIS | 3123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 60accda51efc56684403c685 | 5 | JOHNNY | LOLLOBRIGIDA | 4123456789 | 2006-02-15T04:34:00.330Z | 485125 | 1 | 2022-10-30T03:25:03.000Z | India | | 606b7d364bebce00196eade7 | 6 | JOHNNY | LOLLOBRIGIDA | 5123456789 | 2006-02-15T04:34:00.330Z | 123456 | 2 | 2022-10-30T03:25:03.000Z | India | | 606b75961055000018fa9d98 | 7 | GRACE | MOSTEL | 6123456789 | 2006-02-15T04:34:00.330Z | 356589 | 3 | 2022-10-30T03:25:03.000Z | India | | 6064dd02730026001956663e | 8 | MATTHEW | JOHANSSON | 7123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 6064dcb8730026001956663c | 9 | JOE | SWANK | 8123456789 | 2006-02-15T04:34:00.330Z | 251415 | 1 | 2022-10-30T03:25:03.000Z | India | | 6064c4c02bafb90018955299 | 10 | CHRISTIAN | GABLE | 9123456789 | 2006-02-15T04:34:00.330Z | 100050 | | 2022-10-30T03:25:03.000Z | India | ## Results at a glance Requests per second, the average of two rounds of 15 seconds with 100 connections. *Public* APIs need no token ; *both tokens* means every request carries `x-am-authorization` (the token of an API user, whose groups decide what it may call) and `x-am-user-authorization` (the token of a row of the `customers` table, made by a DB token generator), and API Maker checks both. **Requests per second · 2 vCPU, 4 GB RAM, dedicated CPU** · MongoDB · PostgreSQL · MySQL Get allpublic · 3,712 · 4,782 · 5,418 Get allboth tokens · 3,564 · 4,384 · 4,939 Get all with cachingpublic · 15,152 · 14,883 · 15,123 Get all with cachingboth tokens · 11,750 · 11,615 · 11,626 Get all by streampublic · 3,661 · 4,837 · 5,034 Get all by streamboth tokens · 3,462 · 4,427 · 4,518 Custom API calling get all QuickJS · public · 2,591 · 3,059 · 3,357 Custom API calling get all QuickJS · both tokens · 2,420 · 2,801 · 3,058 Custom API in the sandbox Sandbox · public · 2,269 · 2,389 · 2,714 Get all with a pre hook QuickJS · both tokens · 2,713 · 3,246 · 3,524 Get by idpublic · 4,323 · 5,090 · 5,874 Get by idboth tokens · 4,044 · 4,626 · 5,304 Get by id with cachingpublic · 16,455 · 16,517 · 16,379 Get by id with cachingboth tokens · 12,553 · 12,500 · 12,515 Insert one rowpublic · 1,735 · 2,335 · 2,081 | API | Access | MongoDB | PostgreSQL | MySQL | |---|---|--:|--:|--:| | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all) | Public | **3,712** p99 68 ms | **4,782** p99 24 ms | **5,418** p99 22 ms | | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all) | Both tokens | **3,564** p99 48 ms | **4,384** p99 27 ms | **4,939** p99 24 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-caching) | Public | **15,152** p99 10 ms | **14,883** p99 10 ms | **15,123** p99 9 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-caching) | Both tokens | **11,750** p99 12 ms | **11,615** p99 12 ms | **11,626** p99 13 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-by-stream) | Public | **3,661** p99 50 ms | **4,837** p99 25 ms | **5,034** p99 23 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-by-stream) | Both tokens | **3,462** p99 48 ms | **4,427** p99 26 ms | **4,518** p99 26 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-calling-get-all) QuickJS | Public | **2,591** p99 62 ms | **3,059** p99 37 ms | **3,357** p99 35 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-calling-get-all) QuickJS | Both tokens | **2,420** p99 67 ms | **2,801** p99 41 ms | **3,058** p99 38 ms | | [Custom API in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-in-the-sandbox) Sandbox | Public | **2,269** p99 77 ms | **2,389** p99 72 ms | **2,714** p99 64 ms | | [Get all with a pre hook](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-all-with-a-pre-hook) QuickJS | Both tokens | **2,713** p99 61 ms | **3,246** p99 36 ms | **3,524** p99 59 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id) | Public | **4,323** p99 42 ms | **5,090** p99 22 ms | **5,874** p99 20 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id) | Both tokens | **4,044** p99 41 ms | **4,626** p99 40 ms | **5,304** p99 22 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id-with-caching) | Public | **16,455** p99 9 ms | **16,517** p99 9 ms | **16,379** p99 9 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#get-by-id-with-caching) | Both tokens | **12,553** p99 12 ms | **12,500** p99 12 ms | **12,515** p99 12 ms | | [Insert one row](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#insert-one-row) | Public | **1,735** p99 99 ms | **2,335** p99 49 ms | **2,081** p99 54 ms | | [Custom API without a database](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-without-a-database) | Public | **10,790** p99 13 ms | | | | [Custom API without a database, in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html#custom-api-without-a-database) | Public | **9,953** p99 16 ms | | | (0 errors) Every one of the **10,989,400 requests** of these runs was answered with status 200 or 201 : no error, no timeout. ## Memory What each part of the server held, in MB : at rest (the 60 seconds after API Maker and its sandboxes started, before any request) and under load. The bars show the second the whole server held the most memory while its database was loaded, out of the 3,915 MB of the server ; the table gives the most each part held on its own. API Maker is the resident memory of its process ; a container is counted the way `docker stats` counts it. API Maker · MongoDB of API Maker · Redis · PostgreSQL / MySQL · Sandboxes · Linux, Docker, the rest · Available MongoDB at rest under load PostgreSQL at rest under load MySQL at rest under load | Part | MongoDB
at rest → under load | PostgreSQL
at rest → under load | MySQL
at rest → under load | |---|--:|--:|--:| | **API Maker** (process), in RAM | 99 → **127** | 99 → **120** | 98 → **124** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | MongoDB of API Maker, in RAM | 125 → **234** | 224 → **224** | 224 → **224** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | Redis, in RAM | 3 → **3** | 3 → **3** | 3 → **3** | | Database under test, in RAM | MongoDB above | 41 → **140** | 422 → **492** | | … and in swap | MongoDB above | 0 → **0** | 0 → **0** | | Sandboxes (2 containers), in RAM | 50 → **323** | 50 → **239** | 50 → **238** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | **Whole server**, RAM used | 773 → **1222** | 1000 → **1279** | 1339 → **1600** | | Swap used | 0 → **0** | 0 → **0** | 0 → **0** | ## CPU On 2 vCPUs, API Maker, the database and the sandboxes share the same 2 vCPUs : every request costs the work of all of them. During *get all, public*, the CPU was split this way (average of the 15 seconds, in vCPUs : 2.0 is the whole server ; a process counts its own kernel time) : | | MongoDB | PostgreSQL | MySQL | |---|--:|--:|--:| | API Maker | 0.8 vCPU | 0.9 vCPU | 1.0 vCPU | | The database | 0.8 vCPU | 0.7 vCPU | 0.6 vCPU | | MongoDB of API Maker (when it is not the one tested) | – | 0.0 vCPU | 0.0 vCPU | | Sandboxes (idle : no code runs in get all) | 0.0 vCPU | 0.0 vCPU | 0.0 vCPU | | Whole server busy (of its 2 vCPUs) | 100 % | 98 % | 97 % | | … of which kernel time (network, disk), counted in the lines above too | 35 % | 38 % | 41 % | Steal time (CPU the hypervisor gave to other servers) was 0 % on average, 1 % at most. The load generator, sampled the same way, was never more than 17 % busy over its 8 cores : it was never the limit. ## Get all The schema API of a table answers all its rows : `GET /api/schema////
`. Every request reads the ten rows from the database, converts them with the schema of the table and sends them as JSON. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-api.html). ### Get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 3,712 54,188 requests in 15 s Latency p50 26ms average 27.2 ms Latency p99 68ms max 218 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,812** · 2 : **3,613** req/s · spread 5.3 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.8 vCPU**, **123 MB** RSS · MongoDB **0.8 vCPU** · sandboxes **0.0 vCPU**, **316 MB** · whole server busy **100 %**, of which kernel (network, disk) **35 %** · memory used **1204 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 4,782 71,844 requests in 15 s Latency p50 20ms average 20.4 ms Latency p99 24ms max 30 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,790** · 2 : **4,773** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **107 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **50 MB** · whole server busy **98 %**, of which kernel (network, disk) **38 %** · memory used **979 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 5,418 80,980 requests in 15 s Latency p50 18ms average 18.0 ms Latency p99 22ms max 28 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,438** · 2 : **5,399** req/s · spread 0.7 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **238 MB** · whole server busy **97 %**, of which kernel (network, disk) **41 %** · memory used **1599 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, public · round 2 of 2, the closer to the average ### Get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 3,564 53,764 requests in 15 s Latency p50 27ms average 27.4 ms Latency p99 48ms max 133 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,585** · 2 : **3,544** req/s · spread 1.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **114 MB** RSS · MongoDB **0.8 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **100 %**, of which kernel (network, disk) **34 %** · memory used **830 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 4,384 65,174 requests in 15 s Latency p50 22ms average 22.5 ms Latency p99 27ms max 36 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,423** · 2 : **4,346** req/s · spread 1.8 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **115 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **238 MB** · whole server busy **98 %**, of which kernel (network, disk) **35 %** · memory used **1266 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 4,939 74,517 requests in 15 s Latency p50 20ms average 19.6 ms Latency p99 24ms max 32 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,968** · 2 : **4,910** req/s · spread 1.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **110 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **98 %**, of which kernel (network, disk) **39 %** · memory used **1358 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, both tokens · round 1 of 2, the closer to the average ## Get all with caching The same request on a table whose API settings say `enableCaching: true`. The first answer is kept in Redis, under a key made of who asks and what is asked ; the next requests are answered from Redis until the answer expires or something writes the table. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get all with caching : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 15,152 227,064 requests in 15 s Latency p50 6ms average 6.1 ms Latency p99 10ms max 19 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **15,140** · 2 : **15,165** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.6 vCPU**, **114 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **45 %** · memory used **827 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 14,883 225,090 requests in 15 s Latency p50 6ms average 6.2 ms Latency p99 10ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **15,007** · 2 : **14,759** req/s · spread 1.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.6 vCPU**, **108 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · Redis **0.1 vCPU** · whole server busy **99 %**, of which kernel (network, disk) **45 %** · memory used **968 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 15,123 230,004 requests in 15 s Latency p50 6ms average 6.0 ms Latency p99 9ms max 19 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **15,335** · 2 : **14,911** req/s · spread 2.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.6 vCPU**, **111 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **45 %** · memory used **1342 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, public · round 1 of 2, the closer to the average ### Get all with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 11,750 177,173 requests in 15 s Latency p50 8ms average 8.0 ms Latency p99 12ms max 26 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **11,812** · 2 : **11,689** req/s · spread 1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **113 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **37 %** · memory used **817 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 11,615 176,511 requests in 15 s Latency p50 8ms average 8.0 ms Latency p99 12ms max 23 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **11,768** · 2 : **11,462** req/s · spread 2.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **108 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **38 %** · memory used **967 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 11,626 171,499 requests in 15 s Latency p50 8ms average 8.3 ms Latency p99 13ms max 21 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **11,817** · 2 : **11,434** req/s · spread 3.3 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **238 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **38 %** · memory used **1593 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, both tokens · round 2 of 2, the closer to the average ## Get all by stream `GET …/
/stream` : the rows are sent while they are read from the database cursor, so a large table never sits whole in memory. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-by-stream-api.html). ### Get all by stream : public No token : the API is public. Each answer : 2,477 bytes (MongoDB), status 200. **MongoDB** Requests / second 3,661 54,760 requests in 15 s Latency p50 26ms average 26.9 ms Latency p99 50ms max 209 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,670** · 2 : **3,651** req/s · spread 0.5 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **122 MB** RSS · MongoDB **0.8 vCPU** · sandboxes **0.0 vCPU**, **316 MB** · whole server busy **100 %**, of which kernel (network, disk) **31 %** · memory used **1209 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 4,837 72,185 requests in 15 s Latency p50 20ms average 20.3 ms Latency p99 25ms max 31 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,861** · 2 : **4,813** req/s · spread 1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **238 MB** · whole server busy **98 %**, of which kernel (network, disk) **38 %** · memory used **1278 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, public · round 2 of 2, the closer to the average **MySQL** Requests / second 5,034 76,176 requests in 15 s Latency p50 19ms average 19.2 ms Latency p99 23ms max 30 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,079** · 2 : **4,988** req/s · spread 1.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **98 %**, of which kernel (network, disk) **40 %** · memory used **1346 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, public · round 1 of 2, the closer to the average ### Get all by stream : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,577 bytes (MongoDB), status 200. **MongoDB** Requests / second 3,462 51,150 requests in 15 s Latency p50 29ms average 28.8 ms Latency p99 48ms max 75 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,514** · 2 : **3,411** req/s · spread 3 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **122 MB** RSS · MongoDB **0.7 vCPU** · sandboxes **0.0 vCPU**, **316 MB** · whole server busy **100 %**, of which kernel (network, disk) **30 %** · memory used **1210 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 4,427 66,706 requests in 15 s Latency p50 22ms average 22.0 ms Latency p99 26ms max 36 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,448** · 2 : **4,407** req/s · spread 0.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **113 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **98 %**, of which kernel (network, disk) **37 %** · memory used **974 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 4,518 68,274 requests in 15 s Latency p50 21ms average 21.5 ms Latency p99 26ms max 33 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,552** · 2 : **4,484** req/s · spread 1.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.1 vCPU**, **119 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.5 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **98 %**, of which kernel (network, disk) **37 %** · memory used **1348 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, both tokens · round 1 of 2, the closer to the average ## Custom API calling get all A custom API written in TypeScript, `return await g.sys.db.getAll({ instance, database, collection })`. This code is *lean* : it only reads what it is handed and asks `g.sys` for a read, so API Maker runs it in the server itself, with QuickJS, on the thread which answers the request, and the request never leaves the server. Code which needs more (a package, the time of the machine, `g.shared`, …) runs in the sandbox of the account : see the next API. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API (public : customers_public ; both tokens : customers)** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` ### Custom API calling get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 2,591 39,207 requests in 15 s Latency p50 38ms average 37.7 ms Latency p99 62ms max 86 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,614** · 2 : **2,569** req/s · spread 1.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.2 vCPU**, **124 MB** RSS · MongoDB **0.6 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **885 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,059 46,099 requests in 15 s Latency p50 32ms average 32.0 ms Latency p99 37ms max 46 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,074** · 2 : **3,044** req/s · spread 1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **986 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 3,357 49,816 requests in 15 s Latency p50 30ms average 29.6 ms Latency p99 35ms max 45 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,393** · 2 : **3,321** req/s · spread 2.1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **120 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **238 MB** · whole server busy **100 %**, of which kernel (network, disk) **27 %** · memory used **1588 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, public · round 2 of 2, the closer to the average ### Custom API calling get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 2,420 36,267 requests in 15 s Latency p50 41ms average 40.8 ms Latency p99 67ms max 89 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,418** · 2 : **2,422** req/s · spread 0.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **124 MB** RSS · MongoDB **0.5 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **879 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 2,801 42,514 requests in 15 s Latency p50 35ms average 34.8 ms Latency p99 41ms max 50 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,835** · 2 : **2,768** req/s · spread 2.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **100 %**, of which kernel (network, disk) **24 %** · memory used **988 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 3,058 46,537 requests in 15 s Latency p50 32ms average 31.7 ms Latency p99 38ms max 57 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,103** · 2 : **3,014** req/s · spread 2.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.4 vCPU**, **119 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **51 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **1350 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, both tokens · round 1 of 2, the closer to the average ## Custom API in the sandbox The same custom API, with one line more : it reads `Date.now()`, the time of the machine, which lean code may not. So this code runs in a sandbox of the account (a container with Node.js 24) : the request goes from API Maker to a runner of the sandbox and back, and the rows are read from inside the sandbox by the core of API Maker loaded there. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API which runs in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const started = Date.now(); // the time of the machine : this code runs in the sandbox of the account return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 2,269 34,163 requests in 15 s Latency p50 42ms average 43.4 ms Latency p99 77ms max 128 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,261** · 2 : **2,278** req/s · spread 0.8 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **121 MB** RSS · MongoDB **0.5 vCPU** · sandboxes **0.9 vCPU**, **300 MB** · whole server busy **100 %**, of which kernel (network, disk) **22 %** · memory used **1189 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api in the sandbox, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 2,389 35,955 requests in 15 s Latency p50 40ms average 41.2 ms Latency p99 72ms max 97 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,398** · 2 : **2,381** req/s · spread 0.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.5 vCPU**, **112 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.4 vCPU** · sandboxes **0.8 vCPU**, **218 MB** · whole server busy **100 %**, of which kernel (network, disk) **26 %** · memory used **1223 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api in the sandbox, public · round 1 of 2, the closer to the average **MySQL** Requests / second 2,714 40,795 requests in 15 s Latency p50 35ms average 36.3 ms Latency p99 64ms max 87 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,708** · 2 : **2,720** req/s · spread 0.4 % · the output below is round 2, the closer to the average (Server during this run) API Maker **0.6 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.3 vCPU** · sandboxes **0.9 vCPU**, **226 MB** · whole server busy **100 %**, of which kernel (network, disk) **28 %** · memory used **1582 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api in the sandbox, public · round 2 of 2, the closer to the average ## Get all with a pre hook Get all, with both tokens, on a table whose get all API has a pre hook written in TypeScript : before the API, the hook runs (lean code : in the server, with QuickJS), reads the signed-in person from `x-am-user-authorization` and keeps the rows of their country (`g.req.query.find`), the row scoping most applications need. Every row of the dataset is in India, as the person is, so the answer is the same ten rows. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html). **The pre hook of SCHEMA_GET_ALL on customers_pre_hook** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { if (!g.req.isApiRequestFromUser) return; const person = g.req.auth.authAMDB; // the person, from x-am-user-authorization if (!person) throw [{ code: T.EStatusCode.UNAUTHORIZED, message: 'Sign in first.' }]; const find = g.req.query.find ? (typeof g.req.query.find === 'string' ? JSON.parse(g.req.query.find) : g.req.query.find) : {}; g.req.query.find = { $and: [find, { country: person.country }] }; } module.exports = main; ``` With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 2,713 40,651 requests in 15 s Latency p50 36ms average 36.4 ms Latency p99 61ms max 101 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,711** · 2 : **2,716** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.1 vCPU**, **122 MB** RSS · MongoDB **0.7 vCPU** · sandboxes **0.0 vCPU**, **323 MB** · whole server busy **100 %**, of which kernel (network, disk) **27 %** · memory used **1185 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 3,246 48,540 requests in 15 s Latency p50 30ms average 30.4 ms Latency p99 36ms max 49 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,256** · 2 : **3,237** req/s · spread 0.6 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.2 vCPU**, **114 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.5 vCPU** · sandboxes **0.0 vCPU**, **217 MB** · whole server busy **100 %**, of which kernel (network, disk) **26 %** · memory used **1239 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with a pre hook, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 3,524 52,154 requests in 15 s Latency p50 27ms average 28.3 ms Latency p99 59ms max 73 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,478** · 2 : **3,569** req/s · spread 2.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.2 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.4 vCPU** · sandboxes **0.0 vCPU**, **216 MB** · whole server busy **100 %**, of which kernel (network, disk) **29 %** · memory used **1573 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average ## Get by id One row by its primary key : `GET …/
/get-by-id/`. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-by-id-api.html). ### Get by id : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,323 65,098 requests in 15 s Latency p50 22ms average 22.5 ms Latency p99 42ms max 109 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,340** · 2 : **4,306** req/s · spread 0.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **122 MB** RSS · MongoDB **0.8 vCPU** · sandboxes **0.0 vCPU**, **322 MB** · whole server busy **100 %**, of which kernel (network, disk) **34 %** · memory used **1167 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 5,090 78,172 requests in 15 s Latency p50 19ms average 18.7 ms Latency p99 22ms max 30 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,212** · 2 : **4,968** req/s · spread 4.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.8 vCPU**, **113 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.8 vCPU** · sandboxes **0.0 vCPU**, **218 MB** · whole server busy **98 %**, of which kernel (network, disk) **37 %** · memory used **1222 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, public · round 1 of 2, the closer to the average **MySQL** Requests / second 5,874 88,481 requests in 15 s Latency p50 16ms average 16.4 ms Latency p99 20ms max 28 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,849** · 2 : **5,899** req/s · spread 0.9 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **216 MB** · whole server busy **98 %**, of which kernel (network, disk) **41 %** · memory used **1576 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, public · round 2 of 2, the closer to the average ### Get by id : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,044 60,933 requests in 15 s Latency p50 24ms average 24.1 ms Latency p99 41ms max 85 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,025** · 2 : **4,063** req/s · spread 0.9 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **123 MB** RSS · MongoDB **0.7 vCPU** · sandboxes **0.0 vCPU**, **213 MB** · whole server busy **100 %**, of which kernel (network, disk) **32 %** · memory used **1116 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 4,626 69,317 requests in 15 s Latency p50 20ms average 21.1 ms Latency p99 40ms max 59 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,622** · 2 : **4,631** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.9 vCPU**, **114 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **218 MB** · whole server busy **98 %**, of which kernel (network, disk) **34 %** · memory used **1231 MB** of 3915 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 5,304 79,346 requests in 15 s Latency p50 18ms average 18.4 ms Latency p99 22ms max 31 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,290** · 2 : **5,318** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.6 vCPU** · sandboxes **0.0 vCPU**, **216 MB** · whole server busy **98 %**, of which kernel (network, disk) **36 %** · memory used **1561 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, both tokens · round 1 of 2, the closer to the average ## Get by id with caching One row by its primary key, on a table with `enableCaching: true` : answered from Redis after the first request. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get by id with caching : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 16,455 245,386 requests in 15 s Latency p50 6ms average 5.6 ms Latency p99 9ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **16,358** · 2 : **16,552** req/s · spread 1.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.6 vCPU**, **120 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **215 MB** · Redis **0.1 vCPU** · whole server busy **99 %**, of which kernel (network, disk) **41 %** · memory used **1074 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 16,517 249,145 requests in 15 s Latency p50 5ms average 5.5 ms Latency p99 9ms max 19 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **16,610** · 2 : **16,423** req/s · spread 1.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.6 vCPU**, **113 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **218 MB** · Redis **0.1 vCPU** · whole server busy **99 %**, of which kernel (network, disk) **41 %** · memory used **1243 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 16,379 250,574 requests in 15 s Latency p50 5ms average 5.5 ms Latency p99 9ms max 21 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **16,705** · 2 : **16,053** req/s · spread 4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.6 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **216 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **41 %** · memory used **1564 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, public · round 1 of 2, the closer to the average ### Get by id with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 12,553 186,441 requests in 15 s Latency p50 8ms average 7.5 ms Latency p99 12ms max 24 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,430** · 2 : **12,675** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **215 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **34 %** · memory used **1042 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 12,500 189,138 requests in 15 s Latency p50 7ms average 7.4 ms Latency p99 12ms max 24 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,610** · 2 : **12,390** req/s · spread 1.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **113 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **218 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **34 %** · memory used **1246 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 12,515 189,084 requests in 15 s Latency p50 7ms average 7.4 ms Latency p99 12ms max 23 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,606** · 2 : **12,423** req/s · spread 1.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **216 MB** · Redis **0.1 vCPU** · whole server busy **100 %**, of which kernel (network, disk) **34 %** · memory used **1565 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, both tokens · round 1 of 2, the closer to the average ## Insert one row `POST …/
/save-single-or-multiple` with one row of 9 columns in the body : the schema checks and converts it, the database writes it, and the saved row is answered. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html). No token : the API is public. Each answer : 277 bytes (MongoDB), status 201. **MongoDB** Requests / second 1,735 25,621 requests in 15 s Latency p50 58ms average 58.0 ms Latency p99 99ms max 222 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **1,708** · 2 : **1,762** req/s · spread 3.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **123 MB** RSS · MongoDB **1.0 vCPU** · sandboxes **0.0 vCPU**, **214 MB** · whole server busy **100 %**, of which kernel (network, disk) **32 %** · memory used **1099 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MongoDB · insert one row, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 2,335 35,428 requests in 15 s Latency p50 42ms average 41.8 ms Latency p99 49ms max 55 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,362** · 2 : **2,308** req/s · spread 2.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.7 vCPU**, **114 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.8 vCPU** · sandboxes **0.0 vCPU**, **218 MB** · whole server busy **97 %**, of which kernel (network, disk) **37 %** · memory used **1232 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · insert one row, public · round 1 of 2, the closer to the average **MySQL** Requests / second 2,081 30,894 requests in 15 s Latency p50 48ms average 48.0 ms Latency p99 54ms max 63 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **2,060** · 2 : **2,102** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **0.6 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **216 MB** · whole server busy **93 %**, of which kernel (network, disk) **42 %** · memory used **1558 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · MySQL · insert one row, public · round 1 of 2, the closer to the average ## Custom API without a database A public custom API whose code returns a small object and reads no database : what running code of the account costs, without a database. Lean code runs in the server itself, with QuickJS ; the same code with `Date.now()` in it runs in a sandbox of the account : the trip from API Maker to the runner in its container and back. **In the server (lean code)** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from API Maker', time: 1 }; } module.exports = main; ``` Requests / second 10,790 162,138 requests in 15 s Latency p50 9ms average 8.8 ms Latency p99 13ms max 22 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **10,810** · 2 : **10,771** req/s · spread 0.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **315 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **1187 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the server (lean code) · round 1 of 2, the closer to the average **In the sandbox** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from the sandbox', time: Date.now() }; } module.exports = main; ``` Requests / second 9,953 149,055 requests in 15 s Latency p50 10ms average 9.6 ms Latency p99 16ms max 25 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,968** · 2 : **9,938** req/s · spread 0.3 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **120 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.6 vCPU**, **314 MB** · whole server busy **100 %**, of which kernel (network, disk) **28 %** · memory used **1197 MB** of 3916 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the sandbox · round 2 of 2, the closer to the average ## More connections *Get all, public* and *Get by id with caching, public* on MongoDB, one run of 15 seconds for each number of connections. More clients at once wait longer for their answer, and the server keeps answering them all. ### Get all, public, by connections **Get all, public, MongoDB : requests per second by connections** 10 connectionsp50 2 ms · p99 5 ms · 3,698 50 connectionsp50 12 ms · p99 24 ms · 3,830 100 connectionsp50 25 ms · p99 67 ms · 3,769 250 connectionsp50 69 ms · p99 128 ms · 3,483 500 connectionsp50 139 ms · p99 163 ms · 3,578 1,000 connectionsp50 277 ms · p99 309 ms · 3,572 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **3,698** | 2 ms | 5 ms | 12 ms | 0 | 97 % | 115 MB | | 50 | **3,830** | 12 ms | 24 ms | 81 ms | 0 | 100 % | 118 MB | | 100 | **3,769** | 25 ms | 67 ms | 206 ms | 0 | 100 % | 122 MB | | 250 | **3,483** | 69 ms | 128 ms | 194 ms | 0 | 100 % | 133 MB | | 500 | **3,578** | 139 ms | 163 ms | 246 ms | 0 | 100 % | 148 MB | | 1,000 | **3,572** | 277 ms | 309 ms | 399 ms | 0 | 100 % | 182 MB | ### Get by id with caching, public, by connections **Get by id with caching, public, MongoDB : requests per second by connections** 10 connectionsp50 0 ms · p99 1 ms · 11,206 50 connectionsp50 3 ms · p99 5 ms · 15,740 100 connectionsp50 6 ms · p99 9 ms · 16,389 250 connectionsp50 14 ms · p99 20 ms · 16,938 500 connectionsp50 29 ms · p99 38 ms · 16,599 1,000 connectionsp50 72 ms · p99 83 ms · 13,672 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **11,206** | 0 ms | 1 ms | 7 ms | 0 | 90 % | 120 MB | | 50 | **15,740** | 3 ms | 5 ms | 12 ms | 0 | 99 % | 119 MB | | 100 | **16,389** | 6 ms | 9 ms | 21 ms | 0 | 100 % | 121 MB | | 250 | **16,938** | 14 ms | 20 ms | 45 ms | 0 | 100 % | 131 MB | | 500 | **16,599** | 29 ms | 38 ms | 69 ms | 0 | 100 % | 146 MB | | 1,000 | **13,672** | 72 ms | 83 ms | 156 ms | 0 | 100 % | 174 MB | ## Questions ### How many requests per second can API Maker serve on 2 dedicated vCPUs ? On this 4 GB server, with the database on the same machine : 3,712 requests per second for a whole table of ten rows on MongoDB (PostgreSQL 4,782 · MySQL 5,418), 4,323 for one row by its id, and 16,455 when the answer is cached in Redis. A custom API in TypeScript which reads the table answers 2,591 requests per second when API Maker runs it itself (lean code), 2,269 when it runs in the sandbox of the account. ### How much memory does API Maker use ? The API Maker process held 99 MB at rest and 127 MB at most under load on this server, in RAM. The rest of the memory went to the databases (MongoDB, Redis, PostgreSQL or MySQL), the sandboxes which run the code of the account, and Linux itself. ### Do the two tokens slow the APIs down ? API Maker checks both tokens (x-am-authorization and x-am-user-authorization) and the groups of the API user on every request. Get all with both tokens answered 3,564 requests per second on MongoDB (public : 3,712), 4,384 requests per second on PostgreSQL (public : 4,782), 4,939 requests per second on MySQL (public : 5,418). The checks show most where the database does no work : a cached get all answered 11,750 requests per second with both tokens against 15,152 public on MongoDB. ### What does a pre hook cost ? A pre hook runs code of the account before the API ; a lean hook like this one runs in the server itself, with QuickJS. Get all with a row scoping pre hook answered 2,713 requests per second on MongoDB, against 3,564 for the same API without the hook. On 2 vCPUs, the API, the hook and the database share the same 2 vCPUs. ### Can I run these benchmarks myself ? Yes : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html) gives the dataset, the settings of every API and the exact autocannon commands. --- # API Maker benchmark : 4 vCPU, 8 GB RAM (Linode dedicated CPU) > API Maker on 4 dedicated vCPUs, 8 GB (Linode) : 7,614 req/s get all, 32,588 cached, on MongoDB, PostgreSQL and MySQL, with memory and autocannon output. Source: https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html Benchmark · Linode (Akamai Cloud) · Dedicated CPU · 12 October 2026 **4 vCPU, 8 GB RAM : 7,614 to 10,000 requests per second for a whole table.** API Maker 4.0.0 on a Linode Dedicated 8 GB (g6-dedicated-4) : 4 dedicated vCPUs and 8 GB of RAM at $72 a month, its databases on the same machine. Every API was loaded for 15 seconds by autocannon from a second server, two times, on MongoDB, PostgreSQL and MySQL, public and with two tokens, while the server sampled the memory and CPU of every part each second. Get all · MongoDB 7,614req/s PostgreSQL 8,912 · MySQL 10,000 Get by id, cached 32,588req/s answered from Redis · PostgreSQL 33,015 · MySQL 32,897 Custom API · MongoDB 5,228req/s TypeScript, lean : run in the server · in the sandbox 4,491 API Maker memory 104MB at rest · 140 MB at most under load ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Dedicated 8 GB (g6-dedicated-4), dedicated cpu, $72 / month | | CPU | AMD EPYC 7642 48-Core Processor, 4 dedicated vCPUs (KVM)
KVM guest, 1 thread per core · L1d 256 KiB (4 instances) · L2 2 MiB (4 instances) · L3 64 MiB (4 instances) · BogoMIPS 4599.99 | | Memory | 8 GB (7,941 MB usable), swap 8.3 GB (496 MB of Linode + 7.8 GB made by the installer) | | Disk, region | 160 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 864bb64 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer (lean code of the account runs in the server with QuickJS : sandbox.codeInServer), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) · PostgreSQL 18.6 (official image postgres:18, max_connections 500) · MySQL 8.4.11 (official image mysql:8.4, max_connections 500) : all on the same server | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 403 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default), each opening up to 4 runners when it is busy (one per vCPU) | | Load generator | Dedicated 32 GB (g6-dedicated-16) : AMD EPYC 7642 48-Core Processor, 16 dedicated vCPUs, Ubuntu 24.04.4 LTS, Node.js 24.21.0, autocannon 8.0.0 with 10 worker threads | | Network | Private network of the same data centre, round trip 0.32 ms (ping) | | Host | A strict anti-affinity placement group kept the three dedicated CPU servers (2, 4 and 8 vCPUs) on three different hosts. All seven servers were measured at the same time, each by a load generator of its own. | | Date | 12 October 2026, 05:30 to 06:44 UTC | Only what a database needs was running while it was measured : API Maker and its two sandboxes, its MongoDB and Redis (API Maker always needs them) and the database under test. The other benchmark databases were stopped, API Maker was restarted and the swap emptied back into memory before each database, when it fitted there. How every number was taken : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/summary.html). ## The data Every table holds the ten rows of the [API Maker benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) : `https://apimaker.dev/json/benchmark_dataset.json`. Ten customers, ten columns each ; a *get all* answers all ten (2,418 bytes of JSON on MongoDB), a *get by id* one of them. | `_id` | `customer_id` | `first_name` | `last_name` | `phone` | `last_update` | `pincode` | `shipping_id` | `dob` | `country` | |---|---|---|---|---|---|---|---|---|---| | 60ae2488c37cd955cc144161 | 2 | NICK | WAHLBERG | 1123456789 | 2006-02-15T04:34:00.330Z | 111111 | 2 | 2022-10-30T03:25:03.000Z | India | | 60ae24c8c37cd955cc144162 | 1 | PENELOPE | GUINESS | 123456789 | 2006-02-15T04:34:00.330Z | 100050 | 1 | 2022-10-30T03:25:03.000Z | India | | 60ae247ac37cd955cc144160 | 3 | ED | CHASE | 2123456789 | 2006-02-15T04:34:00.330Z | 222222 | 3 | 2022-10-30T03:25:03.000Z | India | | 60ace1401efc56684403c68c | 4 | JENNIFER | DAVIS | 3123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 60accda51efc56684403c685 | 5 | JOHNNY | LOLLOBRIGIDA | 4123456789 | 2006-02-15T04:34:00.330Z | 485125 | 1 | 2022-10-30T03:25:03.000Z | India | | 606b7d364bebce00196eade7 | 6 | JOHNNY | LOLLOBRIGIDA | 5123456789 | 2006-02-15T04:34:00.330Z | 123456 | 2 | 2022-10-30T03:25:03.000Z | India | | 606b75961055000018fa9d98 | 7 | GRACE | MOSTEL | 6123456789 | 2006-02-15T04:34:00.330Z | 356589 | 3 | 2022-10-30T03:25:03.000Z | India | | 6064dd02730026001956663e | 8 | MATTHEW | JOHANSSON | 7123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 6064dcb8730026001956663c | 9 | JOE | SWANK | 8123456789 | 2006-02-15T04:34:00.330Z | 251415 | 1 | 2022-10-30T03:25:03.000Z | India | | 6064c4c02bafb90018955299 | 10 | CHRISTIAN | GABLE | 9123456789 | 2006-02-15T04:34:00.330Z | 100050 | | 2022-10-30T03:25:03.000Z | India | ## Results at a glance Requests per second, the average of two rounds of 15 seconds with 100 connections. *Public* APIs need no token ; *both tokens* means every request carries `x-am-authorization` (the token of an API user, whose groups decide what it may call) and `x-am-user-authorization` (the token of a row of the `customers` table, made by a DB token generator), and API Maker checks both. **Requests per second · 4 vCPU, 8 GB RAM, dedicated CPU** · MongoDB · PostgreSQL · MySQL Get allpublic · 7,614 · 8,912 · 10,000 Get allboth tokens · 7,220 · 8,245 · 9,236 Get all with cachingpublic · 29,762 · 30,205 · 30,217 Get all with cachingboth tokens · 23,619 · 24,179 · 24,025 Get all by streampublic · 7,342 · 9,098 · 9,458 Get all by streamboth tokens · 6,933 · 8,490 · 8,733 Custom API calling get all QuickJS · public · 5,228 · 5,886 · 6,513 Custom API calling get all QuickJS · both tokens · 4,933 · 5,442 · 6,032 Custom API in the sandbox Sandbox · public · 4,491 · 4,673 · 5,174 Get all with a pre hook QuickJS · both tokens · 5,460 · 6,280 · 6,820 Get by idpublic · 8,777 · 9,655 · 10,654 Get by idboth tokens · 8,182 · 8,790 · 9,758 Get by id with cachingpublic · 32,588 · 33,015 · 32,897 Get by id with cachingboth tokens · 25,516 · 25,875 · 25,837 Insert one rowpublic · 3,574 · 4,236 · 3,462 | API | Access | MongoDB | PostgreSQL | MySQL | |---|---|--:|--:|--:| | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all) | Public | **7,614** p99 28 ms | **8,912** p99 13 ms | **10,000** p99 11 ms | | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all) | Both tokens | **7,220** p99 27 ms | **8,245** p99 14 ms | **9,236** p99 12 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-caching) | Public | **29,762** p99 5 ms | **30,205** p99 5 ms | **30,217** p99 5 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-caching) | Both tokens | **23,619** p99 6 ms | **24,179** p99 6 ms | **24,025** p99 6 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-by-stream) | Public | **7,342** p99 27 ms | **9,098** p99 13 ms | **9,458** p99 12 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-by-stream) | Both tokens | **6,933** p99 26 ms | **8,490** p99 13 ms | **8,733** p99 13 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-calling-get-all) QuickJS | Public | **5,228** p99 32 ms | **5,886** p99 19 ms | **6,513** p99 17 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-calling-get-all) QuickJS | Both tokens | **4,933** p99 35 ms | **5,442** p99 21 ms | **6,032** p99 19 ms | | [Custom API in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-in-the-sandbox) Sandbox | Public | **4,491** p99 41 ms | **4,673** p99 38 ms | **5,174** p99 35 ms | | [Get all with a pre hook](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-all-with-a-pre-hook) QuickJS | Both tokens | **5,460** p99 31 ms | **6,280** p99 18 ms | **6,820** p99 17 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id) | Public | **8,777** p99 22 ms | **9,655** p99 12 ms | **10,654** p99 11 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id) | Both tokens | **8,182** p99 22 ms | **8,790** p99 13 ms | **9,758** p99 12 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id-with-caching) | Public | **32,588** p99 4 ms | **33,015** p99 4 ms | **32,897** p99 4 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#get-by-id-with-caching) | Both tokens | **25,516** p99 6 ms | **25,875** p99 5 ms | **25,837** p99 5 ms | | [Insert one row](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#insert-one-row) | Public | **3,574** p99 52 ms | **4,236** p99 28 ms | **3,462** p99 33 ms | | [Custom API without a database](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-without-a-database) | Public | **21,532** p99 8 ms | | | | [Custom API without a database, in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html#custom-api-without-a-database) | Public | **18,562** p99 10 ms | | | (0 errors) Every one of the **21,624,231 requests** of these runs was answered with status 200 or 201 : no error, no timeout. ## Memory What each part of the server held, in MB : at rest (the 60 seconds after API Maker and its sandboxes started, before any request) and under load. The bars show the second the whole server held the most memory while its database was loaded, out of the 7,941 MB of the server ; the table gives the most each part held on its own. API Maker is the resident memory of its process ; a container is counted the way `docker stats` counts it. API Maker · MongoDB of API Maker · Redis · PostgreSQL / MySQL · Sandboxes · Linux, Docker, the rest · Available MongoDB at rest under load PostgreSQL at rest under load MySQL at rest under load | Part | MongoDB
at rest → under load | PostgreSQL
at rest → under load | MySQL
at rest → under load | |---|--:|--:|--:| | **API Maker** (process), in RAM | 104 → **140** | 105 → **132** | 106 → **133** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | MongoDB of API Maker, in RAM | 126 → **305** | 291 → **292** | 291 → **292** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | Redis, in RAM | 3 → **4** | 3 → **4** | 3 → **4** | | Database under test, in RAM | MongoDB above | 38 → **213** | 421 → **505** | | … and in swap | MongoDB above | 0 → **0** | 0 → **0** | | Sandboxes (2 containers), in RAM | 55 → **515** | 55 → **481** | 53 → **505** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | **Whole server**, RAM used | 872 → **1561** | 1079 → **1723** | 1457 → **2024** | | Swap used | 0 → **0** | 0 → **0** | 0 → **0** | ## CPU On 4 vCPUs, API Maker, the database and the sandboxes share the same 4 vCPUs : every request costs the work of all of them. During *get all, public*, the CPU was split this way (average of the 15 seconds, in vCPUs : 4.0 is the whole server ; a process counts its own kernel time) : | | MongoDB | PostgreSQL | MySQL | |---|--:|--:|--:| | API Maker | 1.7 vCPU | 1.7 vCPU | 1.7 vCPU | | The database | 1.7 vCPU | 1.3 vCPU | 1.2 vCPU | | MongoDB of API Maker (when it is not the one tested) | – | 0.0 vCPU | 0.0 vCPU | | Sandboxes (idle : no code runs in get all) | 0.0 vCPU | 0.0 vCPU | 0.0 vCPU | | Whole server busy (of its 4 vCPUs) | 99 % | 90 % | 90 % | | … of which kernel time (network, disk), counted in the lines above too | 35 % | 35 % | 39 % | Steal time (CPU the hypervisor gave to other servers) was 0 % on average, 0 % at most. The load generator, sampled the same way, was never more than 16 % busy over its 16 cores : it was never the limit. ## Get all The schema API of a table answers all its rows : `GET /api/schema////
`. Every request reads the ten rows from the database, converts them with the schema of the table and sends them as JSON. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-api.html). ### Get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 7,614 116,261 requests in 15 s Latency p50 12ms average 12.4 ms Latency p99 28ms max 69 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,751** · 2 : **7,476** req/s · spread 3.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **123 MB** RSS · MongoDB **1.7 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **99 %**, of which kernel (network, disk) **35 %** · memory used **916 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 8,912 134,114 requests in 15 s Latency p50 11ms average 10.7 ms Latency p99 13ms max 18 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,941** · 2 : **8,883** req/s · spread 0.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **116 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.3 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **90 %**, of which kernel (network, disk) **35 %** · memory used **1103 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 10,000 152,379 requests in 15 s Latency p50 9ms average 9.3 ms Latency p99 11ms max 18 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **10,160** · 2 : **9,840** req/s · spread 3.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.2 vCPU** · sandboxes **0.0 vCPU**, **53 MB** · whole server busy **90 %**, of which kernel (network, disk) **39 %** · memory used **1480 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, public · round 1 of 2, the closer to the average ### Get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 7,220 107,315 requests in 15 s Latency p50 13ms average 13.5 ms Latency p99 27ms max 57 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,285** · 2 : **7,155** req/s · spread 1.8 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.9 vCPU**, **132 MB** RSS · MongoDB **1.5 vCPU** · sandboxes **0.0 vCPU**, **510 MB** · whole server busy **99 %**, of which kernel (network, disk) **33 %** · memory used **1513 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 8,245 124,348 requests in 15 s Latency p50 12ms average 11.6 ms Latency p99 14ms max 21 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,291** · 2 : **8,200** req/s · spread 1.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.9 vCPU**, **117 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.2 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **91 %**, of which kernel (network, disk) **34 %** · memory used **1105 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 9,236 137,909 requests in 15 s Latency p50 10ms average 10.4 ms Latency p99 12ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,277** · 2 : **9,196** req/s · spread 0.9 % · the output below is round 2, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **127 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.1 vCPU** · sandboxes **0.0 vCPU**, **505 MB** · whole server busy **92 %**, of which kernel (network, disk) **37 %** · memory used **2018 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, both tokens · round 2 of 2, the closer to the average ## Get all with caching The same request on a table whose API settings say `enableCaching: true`. The first answer is kept in Redis, under a key made of who asks and what is asked ; the next requests are answered from Redis until the answer expires or something writes the table. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get all with caching : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 29,762 450,257 requests in 15 s Latency p50 3ms average 2.8 ms Latency p99 5ms max 16 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **30,018** · 2 : **29,507** req/s · spread 1.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **123 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **95 %**, of which kernel (network, disk) **42 %** · memory used **901 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 30,205 455,735 requests in 15 s Latency p50 3ms average 2.8 ms Latency p99 5ms max 13 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **30,384** · 2 : **30,026** req/s · spread 1.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **95 %**, of which kernel (network, disk) **42 %** · memory used **1104 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 30,217 458,018 requests in 15 s Latency p50 3ms average 2.8 ms Latency p99 5ms max 212 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **30,535** · 2 : **29,898** req/s · spread 2.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **53 MB** · Redis **0.2 vCPU** · whole server busy **95 %**, of which kernel (network, disk) **42 %** · memory used **1481 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, public · round 1 of 2, the closer to the average ### Get all with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 23,619 355,519 requests in 15 s Latency p50 4ms average 3.7 ms Latency p99 6ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **23,702** · 2 : **23,537** req/s · spread 0.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **120 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **97 %**, of which kernel (network, disk) **35 %** · memory used **896 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 24,179 365,574 requests in 15 s Latency p50 4ms average 3.6 ms Latency p99 6ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **24,373** · 2 : **23,985** req/s · spread 1.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **118 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.2 vCPU** · whole server busy **97 %**, of which kernel (network, disk) **35 %** · memory used **1099 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 24,025 365,041 requests in 15 s Latency p50 4ms average 3.6 ms Latency p99 6ms max 14 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **24,333** · 2 : **23,717** req/s · spread 2.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **119 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **53 MB** · Redis **0.2 vCPU** · whole server busy **97 %**, of which kernel (network, disk) **35 %** · memory used **1483 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, both tokens · round 1 of 2, the closer to the average ## Get all by stream `GET …/
/stream` : the rows are sent while they are read from the database cursor, so a large table never sits whole in memory. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-by-stream-api.html). ### Get all by stream : public No token : the API is public. Each answer : 2,477 bytes (MongoDB), status 200. **MongoDB** Requests / second 7,342 111,227 requests in 15 s Latency p50 13ms average 13.0 ms Latency p99 27ms max 79 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,415** · 2 : **7,269** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.8 vCPU**, **129 MB** RSS · MongoDB **1.6 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **99 %**, of which kernel (network, disk) **32 %** · memory used **923 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 9,098 136,731 requests in 15 s Latency p50 10ms average 10.5 ms Latency p99 13ms max 22 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,116** · 2 : **9,079** req/s · spread 0.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **131 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.3 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **90 %**, of which kernel (network, disk) **36 %** · memory used **1126 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, public · round 1 of 2, the closer to the average **MySQL** Requests / second 9,458 144,777 requests in 15 s Latency p50 10ms average 9.9 ms Latency p99 12ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,653** · 2 : **9,264** req/s · spread 4.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.9 vCPU**, **124 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.1 vCPU** · sandboxes **0.0 vCPU**, **53 MB** · whole server busy **92 %**, of which kernel (network, disk) **38 %** · memory used **1489 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, public · round 1 of 2, the closer to the average ### Get all by stream : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,577 bytes (MongoDB), status 200. **MongoDB** Requests / second 6,933 104,966 requests in 15 s Latency p50 13ms average 13.8 ms Latency p99 26ms max 55 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,998** · 2 : **6,867** req/s · spread 1.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **129 MB** RSS · MongoDB **1.5 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **99 %**, of which kernel (network, disk) **30 %** · memory used **936 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 8,490 127,901 requests in 15 s Latency p50 11ms average 11.2 ms Latency p99 13ms max 21 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,527** · 2 : **8,454** req/s · spread 0.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.9 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.2 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **93 %**, of which kernel (network, disk) **34 %** · memory used **1126 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 8,733 129,622 requests in 15 s Latency p50 11ms average 11.1 ms Latency p99 13ms max 23 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,824** · 2 : **8,642** req/s · spread 2.1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **2.1 vCPU**, **130 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.0 vCPU** · sandboxes **0.0 vCPU**, **505 MB** · whole server busy **93 %**, of which kernel (network, disk) **35 %** · memory used **2014 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, both tokens · round 2 of 2, the closer to the average ## Custom API calling get all A custom API written in TypeScript, `return await g.sys.db.getAll({ instance, database, collection })`. This code is *lean* : it only reads what it is handed and asks `g.sys` for a read, so API Maker runs it in the server itself, with QuickJS, on the thread which answers the request, and the request never leaves the server. Code which needs more (a package, the time of the machine, `g.shared`, …) runs in the sandbox of the account : see the next API. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API (public : customers_public ; both tokens : customers)** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` ### Custom API calling get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 5,228 78,614 requests in 15 s Latency p50 18ms average 18.6 ms Latency p99 32ms max 60 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,242** · 2 : **5,214** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.4 vCPU**, **131 MB** RSS · MongoDB **1.2 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **100 %**, of which kernel (network, disk) **25 %** · memory used **950 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 5,886 88,531 requests in 15 s Latency p50 16ms average 16.4 ms Latency p99 19ms max 27 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,902** · 2 : **5,869** req/s · spread 0.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.5 vCPU**, **122 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.9 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **96 %**, of which kernel (network, disk) **25 %** · memory used **1129 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 6,513 98,309 requests in 15 s Latency p50 15ms average 14.8 ms Latency p99 17ms max 23 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,554** · 2 : **6,472** req/s · spread 1.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.6 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **53 MB** · whole server busy **96 %**, of which kernel (network, disk) **27 %** · memory used **1493 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, public · round 1 of 2, the closer to the average ### Custom API calling get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,933 73,535 requests in 15 s Latency p50 20ms average 19.9 ms Latency p99 35ms max 52 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,963** · 2 : **4,903** req/s · spread 1.2 % · the output below is round 2, the closer to the average (Server during this run) API Maker **2.5 vCPU**, **133 MB** RSS · MongoDB **1.1 vCPU** · sandboxes **0.0 vCPU**, **511 MB** · whole server busy **99 %**, of which kernel (network, disk) **23 %** · memory used **1543 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 5,442 82,083 requests in 15 s Latency p50 18ms average 17.8 ms Latency p99 21ms max 27 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,473** · 2 : **5,411** req/s · spread 1.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.6 vCPU**, **123 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.8 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **97 %**, of which kernel (network, disk) **25 %** · memory used **1122 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 6,032 90,466 requests in 15 s Latency p50 16ms average 16.1 ms Latency p99 19ms max 26 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,031** · 2 : **6,034** req/s · spread 0 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.7 vCPU**, **128 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.7 vCPU** · sandboxes **0.0 vCPU**, **53 MB** · whole server busy **97 %**, of which kernel (network, disk) **26 %** · memory used **1489 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, both tokens · round 1 of 2, the closer to the average ## Custom API in the sandbox The same custom API, with one line more : it reads `Date.now()`, the time of the machine, which lean code may not. So this code runs in a sandbox of the account (a container with Node.js 24) : the request goes from API Maker to a runner of the sandbox and back, and the rows are read from inside the sandbox by the core of API Maker loaded there. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API which runs in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const started = Date.now(); // the time of the machine : this code runs in the sandbox of the account return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 4,491 67,027 requests in 15 s Latency p50 21ms average 21.9 ms Latency p99 41ms max 79 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,469** · 2 : **4,512** req/s · spread 1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **127 MB** RSS · MongoDB **1.0 vCPU** · sandboxes **1.9 vCPU**, **501 MB** · whole server busy **100 %**, of which kernel (network, disk) **21 %** · memory used **1388 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api in the sandbox, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 4,673 70,427 requests in 15 s Latency p50 21ms average 20.8 ms Latency p99 38ms max 62 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,651** · 2 : **4,696** req/s · spread 1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **121 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.8 vCPU** · sandboxes **1.8 vCPU**, **481 MB** · whole server busy **99 %**, of which kernel (network, disk) **26 %** · memory used **1693 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api in the sandbox, public · round 2 of 2, the closer to the average **MySQL** Requests / second 5,174 77,268 requests in 15 s Latency p50 19ms average 18.9 ms Latency p99 35ms max 53 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,152** · 2 : **5,196** req/s · spread 0.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.1 vCPU**, **122 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.6 vCPU** · sandboxes **1.8 vCPU**, **486 MB** · whole server busy **99 %**, of which kernel (network, disk) **28 %** · memory used **1977 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api in the sandbox, public · round 1 of 2, the closer to the average ## Get all with a pre hook Get all, with both tokens, on a table whose get all API has a pre hook written in TypeScript : before the API, the hook runs (lean code : in the server, with QuickJS), reads the signed-in person from `x-am-user-authorization` and keeps the rows of their country (`g.req.query.find`), the row scoping most applications need. Every row of the dataset is in India, as the person is, so the answer is the same ten rows. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html). **The pre hook of SCHEMA_GET_ALL on customers_pre_hook** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { if (!g.req.isApiRequestFromUser) return; const person = g.req.auth.authAMDB; // the person, from x-am-user-authorization if (!person) throw [{ code: T.EStatusCode.UNAUTHORIZED, message: 'Sign in first.' }]; const find = g.req.query.find ? (typeof g.req.query.find === 'string' ? JSON.parse(g.req.query.find) : g.req.query.find) : {}; g.req.query.find = { $and: [find, { country: person.country }] }; } module.exports = main; ``` With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 5,460 81,990 requests in 15 s Latency p50 18ms average 17.8 ms Latency p99 31ms max 66 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,466** · 2 : **5,453** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.2 vCPU**, **130 MB** RSS · MongoDB **1.3 vCPU** · sandboxes **0.0 vCPU**, **506 MB** · whole server busy **100 %**, of which kernel (network, disk) **26 %** · memory used **1407 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 6,280 94,601 requests in 15 s Latency p50 15ms average 15.4 ms Latency p99 18ms max 26 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,307** · 2 : **6,253** req/s · spread 0.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.3 vCPU**, **120 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.0 vCPU** · sandboxes **0.0 vCPU**, **470 MB** · whole server busy **96 %**, of which kernel (network, disk) **27 %** · memory used **1657 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 6,820 102,790 requests in 15 s Latency p50 14ms average 14.1 ms Latency p99 17ms max 23 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **6,786** · 2 : **6,853** req/s · spread 1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **2.4 vCPU**, **127 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.9 vCPU** · sandboxes **0.0 vCPU**, **493 MB** · whole server busy **95 %**, of which kernel (network, disk) **29 %** · memory used **2016 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with a pre hook, both tokens · round 2 of 2, the closer to the average ## Get by id One row by its primary key : `GET …/
/get-by-id/`. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-by-id-api.html). ### Get by id : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 8,777 131,470 requests in 15 s Latency p50 11ms average 10.9 ms Latency p99 22ms max 56 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,764** · 2 : **8,790** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.8 vCPU**, **131 MB** RSS · MongoDB **1.6 vCPU** · sandboxes **0.0 vCPU**, **505 MB** · whole server busy **99 %**, of which kernel (network, disk) **34 %** · memory used **1390 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 9,655 147,101 requests in 15 s Latency p50 10ms average 9.7 ms Latency p99 12ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,807** · 2 : **9,503** req/s · spread 3.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.6 vCPU**, **121 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.4 vCPU** · sandboxes **0.0 vCPU**, **470 MB** · whole server busy **92 %**, of which kernel (network, disk) **35 %** · memory used **1643 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, public · round 1 of 2, the closer to the average **MySQL** Requests / second 10,654 159,179 requests in 15 s Latency p50 9ms average 8.9 ms Latency p99 11ms max 18 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **10,612** · 2 : **10,695** req/s · spread 0.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **126 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.1 vCPU** · sandboxes **0.0 vCPU**, **492 MB** · whole server busy **87 %**, of which kernel (network, disk) **36 %** · memory used **1985 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, public · round 1 of 2, the closer to the average ### Get by id : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 8,182 122,215 requests in 15 s Latency p50 12ms average 11.8 ms Latency p99 22ms max 46 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,148** · 2 : **8,215** req/s · spread 0.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **131 MB** RSS · MongoDB **1.4 vCPU** · sandboxes **0.0 vCPU**, **505 MB** · whole server busy **99 %**, of which kernel (network, disk) **33 %** · memory used **1393 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 8,790 131,939 requests in 15 s Latency p50 11ms average 10.9 ms Latency p99 13ms max 21 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,785** · 2 : **8,795** req/s · spread 0.1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.7 vCPU**, **123 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.3 vCPU** · sandboxes **0.0 vCPU**, **468 MB** · whole server busy **90 %**, of which kernel (network, disk) **32 %** · memory used **1689 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 9,758 146,675 requests in 15 s Latency p50 10ms average 9.7 ms Latency p99 12ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,780** · 2 : **9,737** req/s · spread 0.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.9 vCPU**, **127 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.0 vCPU** · sandboxes **0.0 vCPU**, **492 MB** · whole server busy **91 %**, of which kernel (network, disk) **35 %** · memory used **1986 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, both tokens · round 1 of 2, the closer to the average ## Get by id with caching One row by its primary key, on a table with `enableCaching: true` : answered from Redis after the first request. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get by id with caching : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 32,588 486,856 requests in 15 s Latency p50 3ms average 2.6 ms Latency p99 4ms max 12 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **32,458** · 2 : **32,718** req/s · spread 0.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **128 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **505 MB** · Redis **0.2 vCPU** · whole server busy **94 %**, of which kernel (network, disk) **37 %** · memory used **1405 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 33,015 493,728 requests in 15 s Latency p50 3ms average 2.5 ms Latency p99 4ms max 13 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **32,914** · 2 : **33,115** req/s · spread 0.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.2 vCPU**, **121 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **470 MB** · Redis **0.2 vCPU** · whole server busy **94 %**, of which kernel (network, disk) **37 %** · memory used **1649 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 32,897 499,478 requests in 15 s Latency p50 2ms average 2.5 ms Latency p99 4ms max 13 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **33,297** · 2 : **32,497** req/s · spread 2.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.2 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **492 MB** · Redis **0.2 vCPU** · whole server busy **94 %**, of which kernel (network, disk) **38 %** · memory used **1976 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, public · round 1 of 2, the closer to the average ### Get by id with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 25,516 381,272 requests in 15 s Latency p50 3ms average 3.4 ms Latency p99 6ms max 14 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **25,419** · 2 : **25,612** req/s · spread 0.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **127 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **505 MB** · Redis **0.2 vCPU** · whole server busy **96 %**, of which kernel (network, disk) **31 %** · memory used **1370 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 25,875 388,252 requests in 15 s Latency p50 3ms average 3.4 ms Latency p99 5ms max 14 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **25,867** · 2 : **25,882** req/s · spread 0.1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **121 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **468 MB** · Redis **0.2 vCPU** · whole server busy **97 %**, of which kernel (network, disk) **31 %** · memory used **1701 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 25,837 388,702 requests in 15 s Latency p50 3ms average 3.4 ms Latency p99 5ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **25,914** · 2 : **25,761** req/s · spread 0.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **492 MB** · Redis **0.2 vCPU** · whole server busy **97 %**, of which kernel (network, disk) **30 %** · memory used **1982 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, both tokens · round 1 of 2, the closer to the average ## Insert one row `POST …/
/save-single-or-multiple` with one row of 9 columns in the body : the schema checks and converts it, the database writes it, and the saved row is answered. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html). No token : the API is public. Each answer : 277 bytes (MongoDB), status 201. **MongoDB** Requests / second 3,574 53,698 requests in 15 s Latency p50 27ms average 27.4 ms Latency p99 52ms max 124 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,580** · 2 : **3,568** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **132 MB** RSS · MongoDB **2.0 vCPU** · sandboxes **0.0 vCPU**, **505 MB** · whole server busy **97 %**, of which kernel (network, disk) **29 %** · memory used **1457 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MongoDB · insert one row, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 4,236 64,298 requests in 15 s Latency p50 23ms average 22.8 ms Latency p99 28ms max 44 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **4,287** · 2 : **4,185** req/s · spread 2.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.2 vCPU**, **124 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.5 vCPU** · sandboxes **0.0 vCPU**, **470 MB** · whole server busy **85 %**, of which kernel (network, disk) **31 %** · memory used **1674 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · insert one row, public · round 1 of 2, the closer to the average **MySQL** Requests / second 3,462 51,392 requests in 15 s Latency p50 29ms average 28.7 ms Latency p99 33ms max 49 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,427** · 2 : **3,498** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.0 vCPU**, **129 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.1 vCPU** · sandboxes **0.0 vCPU**, **492 MB** · whole server busy **78 %**, of which kernel (network, disk) **33 %** · memory used **1996 MB** of 7941 MB · steal **0 %** · swap not touched autocannon · MySQL · insert one row, public · round 1 of 2, the closer to the average ## Custom API without a database A public custom API whose code returns a small object and reads no database : what running code of the account costs, without a database. Lean code runs in the server itself, with QuickJS ; the same code with `Date.now()` in it runs in a sandbox of the account : the trip from API Maker to the runner in its container and back. **In the server (lean code)** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from API Maker', time: 1 }; } module.exports = main; ``` Requests / second 21,532 323,087 requests in 15 s Latency p50 4ms average 4.2 ms Latency p99 8ms max 19 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **21,526** · 2 : **21,539** req/s · spread 0.1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **4.0 vCPU**, **124 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **507 MB** · whole server busy **100 %**, of which kernel (network, disk) **24 %** · memory used **1508 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the server (lean code) · round 2 of 2, the closer to the average **In the sandbox** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from the sandbox', time: Date.now() }; } module.exports = main; ``` Requests / second 18,562 278,386 requests in 15 s Latency p50 5ms average 4.9 ms Latency p99 10ms max 18 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **18,558** · 2 : **18,566** req/s · spread 0 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.7 vCPU**, **128 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **1.2 vCPU**, **509 MB** · whole server busy **98 %**, of which kernel (network, disk) **27 %** · memory used **1515 MB** of 7942 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the sandbox · round 1 of 2, the closer to the average ## More connections *Get all, public* and *Get by id with caching, public* on MongoDB, one run of 15 seconds for each number of connections. More clients at once wait longer for their answer, and the server keeps answering them all. ### Get all, public, by connections **Get all, public, MongoDB : requests per second by connections** 10 connectionsp50 1 ms · p99 2 ms · 6,558 50 connectionsp50 6 ms · p99 14 ms · 7,616 100 connectionsp50 12 ms · p99 28 ms · 7,565 250 connectionsp50 33 ms · p99 56 ms · 7,278 500 connectionsp50 70 ms · p99 86 ms · 7,099 1,000 connectionsp50 141 ms · p99 157 ms · 7,063 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **6,558** | 1 ms | 2 ms | 11 ms | 0 | 87 % | 123 MB | | 50 | **7,616** | 6 ms | 14 ms | 32 ms | 0 | 98 % | 127 MB | | 100 | **7,565** | 12 ms | 28 ms | 77 ms | 0 | 99 % | 132 MB | | 250 | **7,278** | 33 ms | 56 ms | 113 ms | 0 | 99 % | 144 MB | | 500 | **7,099** | 70 ms | 86 ms | 123 ms | 0 | 99 % | 158 MB | | 1,000 | **7,063** | 141 ms | 157 ms | 211 ms | 0 | 99 % | 194 MB | ### Get by id with caching, public, by connections **Get by id with caching, public, MongoDB : requests per second by connections** 10 connectionsp50 0 ms · p99 1 ms · 15,484 50 connectionsp50 1 ms · p99 2 ms · 29,267 100 connectionsp50 3 ms · p99 4 ms · 32,315 250 connectionsp50 7 ms · p99 12 ms · 32,425 500 connectionsp50 15 ms · p99 22 ms · 31,813 1,000 connectionsp50 32 ms · p99 43 ms · 30,921 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **15,484** | 0 ms | 1 ms | 11 ms | 0 | 68 % | 129 MB | | 50 | **29,267** | 1 ms | 2 ms | 8 ms | 0 | 89 % | 129 MB | | 100 | **32,315** | 3 ms | 4 ms | 13 ms | 0 | 94 % | 133 MB | | 250 | **32,425** | 7 ms | 12 ms | 24 ms | 0 | 97 % | 141 MB | | 500 | **31,813** | 15 ms | 22 ms | 49 ms | 0 | 98 % | 154 MB | | 1,000 | **30,921** | 32 ms | 43 ms | 75 ms | 0 | 98 % | 182 MB | ## Questions ### How many requests per second can API Maker serve on 4 dedicated vCPUs ? On this 8 GB server, with the database on the same machine : 7,614 requests per second for a whole table of ten rows on MongoDB (PostgreSQL 8,912 · MySQL 10,000), 8,777 for one row by its id, and 32,588 when the answer is cached in Redis. A custom API in TypeScript which reads the table answers 5,228 requests per second when API Maker runs it itself (lean code), 4,491 when it runs in the sandbox of the account. ### How much memory does API Maker use ? The API Maker process held 104 MB at rest and 140 MB at most under load on this server, in RAM. The rest of the memory went to the databases (MongoDB, Redis, PostgreSQL or MySQL), the sandboxes which run the code of the account, and Linux itself. ### Do the two tokens slow the APIs down ? API Maker checks both tokens (x-am-authorization and x-am-user-authorization) and the groups of the API user on every request. Get all with both tokens answered 7,220 requests per second on MongoDB (public : 7,614), 8,245 requests per second on PostgreSQL (public : 8,912), 9,236 requests per second on MySQL (public : 10,000). The checks show most where the database does no work : a cached get all answered 23,619 requests per second with both tokens against 29,762 public on MongoDB. ### What does a pre hook cost ? A pre hook runs code of the account before the API ; a lean hook like this one runs in the server itself, with QuickJS. Get all with a row scoping pre hook answered 5,460 requests per second on MongoDB, against 7,220 for the same API without the hook. On 4 vCPUs, the API, the hook and the database share the same 4 vCPUs. ### Can I run these benchmarks myself ? Yes : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html) gives the dataset, the settings of every API and the exact autocannon commands. --- # API Maker benchmark : 8 vCPU, 16 GB RAM (Linode dedicated CPU) > API Maker on 8 dedicated vCPUs, 16 GB (Linode) : 12,640 req/s get all, 47,980 cached, on MongoDB, PostgreSQL and MySQL, with memory and autocannon output. Source: https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html Benchmark · Linode (Akamai Cloud) · Dedicated CPU · 12 October 2026 **8 vCPU, 16 GB RAM : 12,640 to 13,748 requests per second for a whole table.** API Maker 4.0.0 on a Linode Dedicated 16 GB (g6-dedicated-8) : 8 dedicated vCPUs and 16 GB of RAM at $144 a month, its databases on the same machine. Every API was loaded for 15 seconds by autocannon from a second server, two times, on MongoDB, PostgreSQL and MySQL, public and with two tokens, while the server sampled the memory and CPU of every part each second. Get all · MongoDB 12,640req/s PostgreSQL 12,641 · MySQL 13,748 Get by id, cached 47,980req/s answered from Redis · PostgreSQL 47,888 · MySQL 48,818 Custom API · MongoDB 8,893req/s TypeScript, lean : run in the server · in the sandbox 7,569 API Maker memory 111MB at rest · 176 MB at most under load ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Dedicated 16 GB (g6-dedicated-8), dedicated cpu, $144 / month | | CPU | AMD EPYC 7642 48-Core Processor, 8 dedicated vCPUs (KVM)
KVM guest, 1 thread per core · L1d 512 KiB (8 instances) · L2 4 MiB (8 instances) · L3 128 MiB (8 instances) · BogoMIPS 4599.99 | | Memory | 16 GB (15,991 MB usable), swap 8.5 GB (496 MB of Linode + 8 GB made by the installer) | | Disk, region | 320 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 864bb64 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer (lean code of the account runs in the server with QuickJS : sandbox.codeInServer), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) · PostgreSQL 18.6 (official image postgres:18, max_connections 500) · MySQL 8.4.11 (official image mysql:8.4, max_connections 500) : all on the same server | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 403 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default), each opening up to 8 runners when it is busy (one per vCPU) | | Load generator | Dedicated 64 GB (g6-dedicated-32) : AMD EPYC 7642 48-Core Processor, 32 dedicated vCPUs, Ubuntu 24.04.4 LTS, Node.js 24.21.0, autocannon 8.0.0 with 20 worker threads | | Network | Private network of the same data centre, round trip 0.28 ms (ping) | | Host | A strict anti-affinity placement group kept the three dedicated CPU servers (2, 4 and 8 vCPUs) on three different hosts. All seven servers were measured at the same time, each by a load generator of its own. | | Date | 12 October 2026, 05:30 to 06:44 UTC | Only what a database needs was running while it was measured : API Maker and its two sandboxes, its MongoDB and Redis (API Maker always needs them) and the database under test. The other benchmark databases were stopped, API Maker was restarted and the swap emptied back into memory before each database, when it fitted there. How every number was taken : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/summary.html). ## The data Every table holds the ten rows of the [API Maker benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) : `https://apimaker.dev/json/benchmark_dataset.json`. Ten customers, ten columns each ; a *get all* answers all ten (2,418 bytes of JSON on MongoDB), a *get by id* one of them. | `_id` | `customer_id` | `first_name` | `last_name` | `phone` | `last_update` | `pincode` | `shipping_id` | `dob` | `country` | |---|---|---|---|---|---|---|---|---|---| | 60ae2488c37cd955cc144161 | 2 | NICK | WAHLBERG | 1123456789 | 2006-02-15T04:34:00.330Z | 111111 | 2 | 2022-10-30T03:25:03.000Z | India | | 60ae24c8c37cd955cc144162 | 1 | PENELOPE | GUINESS | 123456789 | 2006-02-15T04:34:00.330Z | 100050 | 1 | 2022-10-30T03:25:03.000Z | India | | 60ae247ac37cd955cc144160 | 3 | ED | CHASE | 2123456789 | 2006-02-15T04:34:00.330Z | 222222 | 3 | 2022-10-30T03:25:03.000Z | India | | 60ace1401efc56684403c68c | 4 | JENNIFER | DAVIS | 3123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 60accda51efc56684403c685 | 5 | JOHNNY | LOLLOBRIGIDA | 4123456789 | 2006-02-15T04:34:00.330Z | 485125 | 1 | 2022-10-30T03:25:03.000Z | India | | 606b7d364bebce00196eade7 | 6 | JOHNNY | LOLLOBRIGIDA | 5123456789 | 2006-02-15T04:34:00.330Z | 123456 | 2 | 2022-10-30T03:25:03.000Z | India | | 606b75961055000018fa9d98 | 7 | GRACE | MOSTEL | 6123456789 | 2006-02-15T04:34:00.330Z | 356589 | 3 | 2022-10-30T03:25:03.000Z | India | | 6064dd02730026001956663e | 8 | MATTHEW | JOHANSSON | 7123456789 | 2006-02-15T04:34:00.330Z | 100050 | 4 | 2022-10-30T03:25:03.000Z | India | | 6064dcb8730026001956663c | 9 | JOE | SWANK | 8123456789 | 2006-02-15T04:34:00.330Z | 251415 | 1 | 2022-10-30T03:25:03.000Z | India | | 6064c4c02bafb90018955299 | 10 | CHRISTIAN | GABLE | 9123456789 | 2006-02-15T04:34:00.330Z | 100050 | | 2022-10-30T03:25:03.000Z | India | ## Results at a glance Requests per second, the average of two rounds of 15 seconds with 100 connections. *Public* APIs need no token ; *both tokens* means every request carries `x-am-authorization` (the token of an API user, whose groups decide what it may call) and `x-am-user-authorization` (the token of a row of the `customers` table, made by a DB token generator), and API Maker checks both. **Requests per second · 8 vCPU, 16 GB RAM, dedicated CPU** · MongoDB · PostgreSQL · MySQL Get allpublic · 12,640 · 12,641 · 13,748 Get allboth tokens · 12,106 · 11,913 · 12,712 Get all with cachingpublic · 43,980 · 43,173 · 44,027 Get all with cachingboth tokens · 36,123 · 35,403 · 35,915 Get all by streampublic · 11,898 · 13,073 · 13,095 Get all by streamboth tokens · 11,516 · 12,162 · 12,340 Custom API calling get all QuickJS · public · 8,893 · 9,176 · 9,820 Custom API calling get all QuickJS · both tokens · 8,426 · 8,561 · 9,129 Custom API in the sandbox Sandbox · public · 7,569 · 7,916 · 8,657 Get all with a pre hook QuickJS · both tokens · 9,279 · 9,524 · 10,204 Get by idpublic · 14,224 · 13,571 · 14,510 Get by idboth tokens · 13,443 · 12,656 · 13,517 Get by id with cachingpublic · 47,980 · 47,888 · 48,818 Get by id with cachingboth tokens · 38,521 · 38,045 · 38,544 Insert one rowpublic · 5,490 · 5,874 · 3,542 | API | Access | MongoDB | PostgreSQL | MySQL | |---|---|--:|--:|--:| | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all) | Public | **12,640** p99 17 ms | **12,641** p99 10 ms | **13,748** p99 9 ms | | [Get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all) | Both tokens | **12,106** p99 17 ms | **11,913** p99 10 ms | **12,712** p99 10 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-caching) | Public | **43,980** p99 3 ms | **43,173** p99 3 ms | **44,027** p99 3 ms | | [Get all with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-caching) | Both tokens | **36,123** p99 4 ms | **35,403** p99 4 ms | **35,915** p99 4 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-by-stream) | Public | **11,898** p99 17 ms | **13,073** p99 9 ms | **13,095** p99 9 ms | | [Get all by stream](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-by-stream) | Both tokens | **11,516** p99 18 ms | **12,162** p99 10 ms | **12,340** p99 10 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-calling-get-all) QuickJS | Public | **8,893** p99 20 ms | **9,176** p99 13 ms | **9,820** p99 12 ms | | [Custom API calling get all](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-calling-get-all) QuickJS | Both tokens | **8,426** p99 21 ms | **8,561** p99 14 ms | **9,129** p99 13 ms | | [Custom API in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-in-the-sandbox) Sandbox | Public | **7,569** p99 24 ms | **7,916** p99 22 ms | **8,657** p99 20 ms | | [Get all with a pre hook](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-all-with-a-pre-hook) QuickJS | Both tokens | **9,279** p99 20 ms | **9,524** p99 13 ms | **10,204** p99 13 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id) | Public | **14,224** p99 14 ms | **13,571** p99 9 ms | **14,510** p99 8 ms | | [Get by id](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id) | Both tokens | **13,443** p99 14 ms | **12,656** p99 11 ms | **13,517** p99 9 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id-with-caching) | Public | **47,980** p99 3 ms | **47,888** p99 3 ms | **48,818** p99 3 ms | | [Get by id with caching](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#get-by-id-with-caching) | Both tokens | **38,521** p99 4 ms | **38,045** p99 4 ms | **38,544** p99 4 ms | | [Insert one row](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#insert-one-row) | Public | **5,490** p99 32 ms | **5,874** p99 19 ms | **3,542** p99 38 ms | | [Custom API without a database](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-without-a-database) | Public | **39,192** p99 4 ms | | | | [Custom API without a database, in the sandbox](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html#custom-api-without-a-database) | Public | **27,920** p99 8 ms | | | (0 errors) Every one of the **32,429,901 requests** of these runs was answered with status 200 or 201 : no error, no timeout. ## Memory What each part of the server held, in MB : at rest (the 60 seconds after API Maker and its sandboxes started, before any request) and under load. The bars show the second the whole server held the most memory while its database was loaded, out of the 15,991 MB of the server ; the table gives the most each part held on its own. API Maker is the resident memory of its process ; a container is counted the way `docker stats` counts it. API Maker · MongoDB of API Maker · Redis · PostgreSQL / MySQL · Sandboxes · Linux, Docker, the rest · Available MongoDB at rest under load PostgreSQL at rest under load MySQL at rest under load | Part | MongoDB
at rest → under load | PostgreSQL
at rest → under load | MySQL
at rest → under load | |---|--:|--:|--:| | **API Maker** (process), in RAM | 111 → **176** | 110 → **159** | 107 → **152** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | MongoDB of API Maker, in RAM | 127 → **384** | 369 → **372** | 369 → **372** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | Redis, in RAM | 3 → **4** | 3 → **4** | 3 → **4** | | Database under test, in RAM | MongoDB above | 38 → **320** | 421 → **519** | | … and in swap | MongoDB above | 0 → **0** | 0 → **0** | | Sandboxes (2 containers), in RAM | 55 → **856** | 55 → **818** | 55 → **880** | | … and in swap | 0 → **0** | 0 → **0** | 0 → **0** | | **Whole server**, RAM used | 946 → **2093** | 1232 → **2349** | 1627 → **2602** | | Swap used | 0 → **0** | 0 → **0** | 0 → **0** | ## CPU On 8 vCPUs, API Maker, the database and the sandboxes share the same 8 vCPUs : every request costs the work of all of them. During *get all, public*, the CPU was split this way (average of the 15 seconds, in vCPUs : 8.0 is the whole server ; a process counts its own kernel time) : | | MongoDB | PostgreSQL | MySQL | |---|--:|--:|--:| | API Maker | 3.3 vCPU | 3.0 vCPU | 2.9 vCPU | | The database | 3.3 vCPU | 1.7 vCPU | 1.6 vCPU | | MongoDB of API Maker (when it is not the one tested) | – | 0.0 vCPU | 0.0 vCPU | | Sandboxes (idle : no code runs in get all) | 0.0 vCPU | 0.0 vCPU | 0.0 vCPU | | Whole server busy (of its 8 vCPUs) | 94 % | 73 % | 72 % | | … of which kernel time (network, disk), counted in the lines above too | 31 % | 28 % | 31 % | Steal time (CPU the hypervisor gave to other servers) was 0 % on average, 7 % at most. The load generator, sampled the same way, was never more than 13 % busy over its 32 cores : it was never the limit. ## Get all The schema API of a table answers all its rows : `GET /api/schema////
`. Every request reads the ten rows from the database, converts them with the schema of the table and sends them as JSON. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-api.html). ### Get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 12,640 192,274 requests in 15 s Latency p50 7ms average 7.3 ms Latency p99 17ms max 44 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,818** · 2 : **12,461** req/s · spread 2.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **131 MB** RSS · MongoDB **3.3 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **94 %**, of which kernel (network, disk) **31 %** · memory used **975 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 12,641 188,004 requests in 15 s Latency p50 7ms average 7.5 ms Latency p99 10ms max 19 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,748** · 2 : **12,534** req/s · spread 1.7 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.0 vCPU**, **139 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.7 vCPU** · sandboxes **0.0 vCPU**, **815 MB** · whole server busy **73 %**, of which kernel (network, disk) **28 %** · memory used **2291 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, public · round 2 of 2, the closer to the average **MySQL** Requests / second 13,748 206,778 requests in 15 s Latency p50 7ms average 6.8 ms Latency p99 9ms max 14 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,785** · 2 : **13,711** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.9 vCPU**, **126 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.6 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **72 %**, of which kernel (network, disk) **31 %** · memory used **1667 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, public · round 1 of 2, the closer to the average ### Get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 12,106 185,158 requests in 15 s Latency p50 7ms average 7.6 ms Latency p99 17ms max 42 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,344** · 2 : **11,868** req/s · spread 3.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.7 vCPU**, **131 MB** RSS · MongoDB **2.9 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **94 %**, of which kernel (network, disk) **30 %** · memory used **990 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 11,913 181,979 requests in 15 s Latency p50 8ms average 7.7 ms Latency p99 10ms max 18 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,133** · 2 : **11,693** req/s · spread 3.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **126 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.7 vCPU** · sandboxes **0.0 vCPU**, **57 MB** · whole server busy **75 %**, of which kernel (network, disk) **27 %** · memory used **1284 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 12,712 192,036 requests in 15 s Latency p50 7ms average 7.3 ms Latency p99 10ms max 16 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,804** · 2 : **12,620** req/s · spread 1.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **129 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.5 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **74 %**, of which kernel (network, disk) **29 %** · memory used **1670 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · get all, both tokens · round 1 of 2, the closer to the average ## Get all with caching The same request on a table whose API settings say `enableCaching: true`. The first answer is kept in Redis, under a key made of who asks and what is asked ; the next requests are answered from Redis until the answer expires or something writes the table. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get all with caching : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 43,980 658,305 requests in 15 s Latency p50 2ms average 1.8 ms Latency p99 3ms max 207 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **44,069** · 2 : **43,890** req/s · spread 0.4 % · the output below is round 2, the closer to the average (Server during this run) API Maker **6.2 vCPU**, **142 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **855 MB** · Redis **0.3 vCPU** · whole server busy **86 %**, of which kernel (network, disk) **34 %** · memory used **2003 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 43,173 649,417 requests in 15 s Latency p50 2ms average 1.8 ms Latency p99 3ms max 10 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **43,052** · 2 : **43,295** req/s · spread 0.6 % · the output below is round 2, the closer to the average (Server during this run) API Maker **6.2 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **814 MB** · Redis **0.3 vCPU** · whole server busy **86 %**, of which kernel (network, disk) **34 %** · memory used **2279 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, public · round 2 of 2, the closer to the average **MySQL** Requests / second 44,027 663,287 requests in 15 s Latency p50 2ms average 1.8 ms Latency p99 3ms max 9 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **44,219** · 2 : **43,835** req/s · spread 0.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.2 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.3 vCPU** · whole server busy **86 %**, of which kernel (network, disk) **34 %** · memory used **1623 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, public · round 1 of 2, the closer to the average ### Get all with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 36,123 535,203 requests in 15 s Latency p50 2ms average 2.3 ms Latency p99 4ms max 10 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **36,562** · 2 : **35,683** req/s · spread 2.4 % · the output below is round 2, the closer to the average (Server during this run) API Maker **6.5 vCPU**, **143 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **855 MB** · Redis **0.3 vCPU** · whole server busy **90 %**, of which kernel (network, disk) **29 %** · memory used **2020 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with caching, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 35,403 528,689 requests in 15 s Latency p50 2ms average 2.3 ms Latency p99 4ms max 212 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **35,560** · 2 : **35,246** req/s · spread 0.9 % · the output below is round 2, the closer to the average (Server during this run) API Maker **6.5 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **814 MB** · Redis **0.3 vCPU** · whole server busy **90 %**, of which kernel (network, disk) **29 %** · memory used **2273 MB** of 15991 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with caching, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 35,915 547,580 requests in 15 s Latency p50 2ms average 2.2 ms Latency p99 4ms max 18 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **36,505** · 2 : **35,325** req/s · spread 3.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.5 vCPU**, **125 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · Redis **0.3 vCPU** · whole server busy **89 %**, of which kernel (network, disk) **29 %** · memory used **1631 MB** of 15991 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with caching, both tokens · round 1 of 2, the closer to the average ## Get all by stream `GET …/
/stream` : the rows are sent while they are read from the database cursor, so a large table never sits whole in memory. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-all-by-stream-api.html). ### Get all by stream : public No token : the API is public. Each answer : 2,477 bytes (MongoDB), status 200. **MongoDB** Requests / second 11,898 176,800 requests in 15 s Latency p50 8ms average 8.0 ms Latency p99 17ms max 52 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,009** · 2 : **11,787** req/s · spread 1.9 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.6 vCPU**, **147 MB** RSS · MongoDB **3.0 vCPU** · sandboxes **0.0 vCPU**, **855 MB** · whole server busy **95 %**, of which kernel (network, disk) **29 %** · memory used **2056 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 13,073 197,970 requests in 15 s Latency p50 7ms average 7.1 ms Latency p99 9ms max 16 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,198** · 2 : **12,947** req/s · spread 1.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.0 vCPU**, **151 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.8 vCPU** · sandboxes **0.0 vCPU**, **57 MB** · whole server busy **74 %**, of which kernel (network, disk) **29 %** · memory used **1307 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, public · round 1 of 2, the closer to the average **MySQL** Requests / second 13,095 196,524 requests in 15 s Latency p50 7ms average 7.1 ms Latency p99 9ms max 218 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,102** · 2 : **13,088** req/s · spread 0.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **145 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.5 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **74 %**, of which kernel (network, disk) **29 %** · memory used **1656 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, public · round 1 of 2, the closer to the average ### Get all by stream : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,577 bytes (MongoDB), status 200. **MongoDB** Requests / second 11,516 173,108 requests in 15 s Latency p50 8ms average 8.2 ms Latency p99 18ms max 55 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **11,542** · 2 : **11,490** req/s · spread 0.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.9 vCPU**, **148 MB** RSS · MongoDB **2.7 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **95 %**, of which kernel (network, disk) **28 %** · memory used **1019 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all by stream, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 12,162 184,136 requests in 15 s Latency p50 8ms average 7.7 ms Latency p99 10ms max 16 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,276** · 2 : **12,048** req/s · spread 1.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **150 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.7 vCPU** · sandboxes **0.0 vCPU**, **57 MB** · whole server busy **76 %**, of which kernel (network, disk) **27 %** · memory used **1310 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all by stream, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 12,340 184,543 requests in 15 s Latency p50 8ms average 7.6 ms Latency p99 10ms max 221 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,303** · 2 : **12,376** req/s · spread 0.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.6 vCPU**, **145 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.4 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **76 %**, of which kernel (network, disk) **28 %** · memory used **1659 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · get all by stream, both tokens · round 1 of 2, the closer to the average ## Custom API calling get all A custom API written in TypeScript, `return await g.sys.db.getAll({ instance, database, collection })`. This code is *lean* : it only reads what it is handed and asks `g.sys` for a read, so API Maker runs it in the server itself, with QuickJS, on the thread which answers the request, and the request never leaves the server. Code which needs more (a package, the time of the machine, `g.shared`, …) runs in the sandbox of the account : see the next API. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API (public : customers_public ; both tokens : customers)** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` ### Custom API calling get all : public No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 8,893 132,169 requests in 15 s Latency p50 11ms average 10.8 ms Latency p99 20ms max 45 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,976** · 2 : **8,810** req/s · spread 1.9 % · the output below is round 2, the closer to the average (Server during this run) API Maker **4.6 vCPU**, **144 MB** RSS · MongoDB **2.3 vCPU** · sandboxes **0.0 vCPU**, **855 MB** · whole server busy **96 %**, of which kernel (network, disk) **23 %** · memory used **2051 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 9,176 138,881 requests in 15 s Latency p50 10ms average 10.3 ms Latency p99 13ms max 18 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,258** · 2 : **9,094** req/s · spread 1.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.6 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.3 vCPU** · sandboxes **0.0 vCPU**, **57 MB** · whole server busy **85 %**, of which kernel (network, disk) **22 %** · memory used **1297 MB** of 15991 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, public · round 1 of 2, the closer to the average **MySQL** Requests / second 9,820 147,636 requests in 15 s Latency p50 10ms average 9.7 ms Latency p99 12ms max 19 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,844** · 2 : **9,796** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.5 vCPU**, **136 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.2 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **82 %**, of which kernel (network, disk) **23 %** · memory used **1653 MB** of 15991 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, public · round 1 of 2, the closer to the average ### Custom API calling get all : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 8,426 127,632 requests in 15 s Latency p50 11ms average 11.3 ms Latency p99 21ms max 36 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,510** · 2 : **8,342** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.9 vCPU**, **143 MB** RSS · MongoDB **2.1 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **97 %**, of which kernel (network, disk) **22 %** · memory used **1033 MB** of 15991 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api calling get all, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 8,561 127,705 requests in 15 s Latency p50 11ms average 11.2 ms Latency p99 14ms max 19 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,607** · 2 : **8,514** req/s · spread 1.1 % · the output below is round 2, the closer to the average (Server during this run) API Maker **4.8 vCPU**, **139 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.2 vCPU** · sandboxes **0.0 vCPU**, **814 MB** · whole server busy **86 %**, of which kernel (network, disk) **20 %** · memory used **2333 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api calling get all, both tokens · round 2 of 2, the closer to the average **MySQL** Requests / second 9,129 136,922 requests in 15 s Latency p50 10ms average 10.5 ms Latency p99 13ms max 21 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,128** · 2 : **9,130** req/s · spread 0 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.8 vCPU**, **138 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.1 vCPU** · sandboxes **0.0 vCPU**, **55 MB** · whole server busy **85 %**, of which kernel (network, disk) **22 %** · memory used **1655 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api calling get all, both tokens · round 1 of 2, the closer to the average ## Custom API in the sandbox The same custom API, with one line more : it reads `Date.now()`, the time of the machine, which lean code may not. So this code runs in a sandbox of the account (a container with Node.js 24) : the request goes from API Maker to a runner of the sandbox and back, and the rows are read from inside the sandbox by the core of API Maker loaded there. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html). **The custom API which runs in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const started = Date.now(); // the time of the machine : this code runs in the sandbox of the account return await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers_public' }); } module.exports = main; ``` No token : the API is public. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 7,569 113,233 requests in 15 s Latency p50 13ms average 12.8 ms Latency p99 24ms max 57 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,550** · 2 : **7,588** req/s · spread 0.5 % · the output below is round 1, the closer to the average (Server during this run) API Maker **1.9 vCPU**, **137 MB** RSS · MongoDB **2.0 vCPU** · sandboxes **3.9 vCPU**, **842 MB** · whole server busy **98 %**, of which kernel (network, disk) **22 %** · memory used **1868 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · custom api in the sandbox, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 7,916 118,732 requests in 15 s Latency p50 12ms average 12.1 ms Latency p99 22ms max 33 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **7,916** · 2 : **7,915** req/s · spread 0 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **133 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.4 vCPU** · sandboxes **3.6 vCPU**, **799 MB** · whole server busy **97 %**, of which kernel (network, disk) **25 %** · memory used **2292 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · custom api in the sandbox, public · round 1 of 2, the closer to the average **MySQL** Requests / second 8,657 129,801 requests in 15 s Latency p50 11ms average 11.1 ms Latency p99 20ms max 30 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **8,654** · 2 : **8,661** req/s · spread 0.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.1 vCPU**, **132 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.1 vCPU** · sandboxes **3.7 vCPU**, **863 MB** · whole server busy **97 %**, of which kernel (network, disk) **27 %** · memory used **2536 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · custom api in the sandbox, public · round 1 of 2, the closer to the average ## Get all with a pre hook Get all, with both tokens, on a table whose get all API has a pre hook written in TypeScript : before the API, the hook runs (lean code : in the server, with QuickJS), reads the signed-in person from `x-am-user-authorization` and keeps the rows of their country (`g.req.query.find`), the row scoping most applications need. Every row of the dataset is in India, as the person is, so the answer is the same ten rows. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html). **The pre hook of SCHEMA_GET_ALL on customers_pre_hook** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { if (!g.req.isApiRequestFromUser) return; const person = g.req.auth.authAMDB; // the person, from x-am-user-authorization if (!person) throw [{ code: T.EStatusCode.UNAUTHORIZED, message: 'Sign in first.' }]; const find = g.req.query.find ? (typeof g.req.query.find === 'string' ? JSON.parse(g.req.query.find) : g.req.query.find) : {}; g.req.query.find = { $and: [find, { country: person.country }] }; } module.exports = main; ``` With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 2,418 bytes (MongoDB), status 200. **MongoDB** Requests / second 9,279 139,353 requests in 15 s Latency p50 10ms average 10.3 ms Latency p99 20ms max 41 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,268** · 2 : **9,290** req/s · spread 0.2 % · the output below is round 2, the closer to the average (Server during this run) API Maker **4.3 vCPU**, **143 MB** RSS · MongoDB **2.7 vCPU** · sandboxes **0.0 vCPU**, **838 MB** · whole server busy **97 %**, of which kernel (network, disk) **25 %** · memory used **2014 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get all with a pre hook, both tokens · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 9,524 144,274 requests in 15 s Latency p50 10ms average 9.9 ms Latency p99 13ms max 17 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **9,618** · 2 : **9,429** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.1 vCPU**, **138 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.6 vCPU** · sandboxes **0.0 vCPU**, **798 MB** · whole server busy **82 %**, of which kernel (network, disk) **24 %** · memory used **2288 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 10,204 153,692 requests in 15 s Latency p50 9ms average 9.3 ms Latency p99 13ms max 20 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **10,247** · 2 : **10,161** req/s · spread 0.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **4.1 vCPU**, **138 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.3 vCPU** · sandboxes **0.0 vCPU**, **864 MB** · whole server busy **81 %**, of which kernel (network, disk) **25 %** · memory used **2544 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · get all with a pre hook, both tokens · round 1 of 2, the closer to the average ## Get by id One row by its primary key : `GET …/
/get-by-id/`. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-get-by-id-api.html). ### Get by id : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 14,224 213,867 requests in 15 s Latency p50 6ms average 6.5 ms Latency p99 14ms max 38 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **14,189** · 2 : **14,259** req/s · spread 0.5 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.4 vCPU**, **144 MB** RSS · MongoDB **3.0 vCPU** · sandboxes **0.0 vCPU**, **838 MB** · whole server busy **93 %**, of which kernel (network, disk) **31 %** · memory used **2012 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, public · round 2 of 2, the closer to the average **PostgreSQL** Requests / second 13,571 205,599 requests in 15 s Latency p50 7ms average 6.8 ms Latency p99 9ms max 14 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,708** · 2 : **13,433** req/s · spread 2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.6 vCPU**, **138 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **2.0 vCPU** · sandboxes **0.0 vCPU**, **798 MB** · whole server busy **72 %**, of which kernel (network, disk) **27 %** · memory used **2282 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, public · round 1 of 2, the closer to the average **MySQL** Requests / second 14,510 218,937 requests in 15 s Latency p50 6ms average 6.3 ms Latency p99 8ms max 215 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **14,597** · 2 : **14,423** req/s · spread 1.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.9 vCPU**, **137 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.6 vCPU** · sandboxes **0.0 vCPU**, **864 MB** · whole server busy **71 %**, of which kernel (network, disk) **29 %** · memory used **2546 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, public · round 1 of 2, the closer to the average ### Get by id : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 13,443 202,576 requests in 15 s Latency p50 7ms average 6.9 ms Latency p99 14ms max 28 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,505** · 2 : **13,382** req/s · spread 0.9 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.9 vCPU**, **143 MB** RSS · MongoDB **2.6 vCPU** · sandboxes **0.0 vCPU**, **839 MB** · whole server busy **93 %**, of which kernel (network, disk) **29 %** · memory used **1819 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 12,656 189,474 requests in 15 s Latency p50 7ms average 7.4 ms Latency p99 11ms max 18 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **12,633** · 2 : **12,679** req/s · spread 0.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **3.0 vCPU**, **139 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **1.9 vCPU** · sandboxes **0.0 vCPU**, **798 MB** · whole server busy **75 %**, of which kernel (network, disk) **26 %** · memory used **2286 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 13,517 202,182 requests in 15 s Latency p50 7ms average 6.9 ms Latency p99 9ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **13,554** · 2 : **13,479** req/s · spread 0.6 % · the output below is round 2, the closer to the average (Server during this run) API Maker **3.3 vCPU**, **138 MB** RSS · MongoDB **0.0 vCPU** · MySQL **1.5 vCPU** · sandboxes **0.0 vCPU**, **863 MB** · whole server busy **73 %**, of which kernel (network, disk) **28 %** · memory used **2563 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id, both tokens · round 2 of 2, the closer to the average ## Get by id with caching One row by its primary key, on a table with `enableCaching: true` : answered from Redis after the first request. [About this API](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). ### Get by id with caching : public No token : the API is public. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 47,980 713,371 requests in 15 s Latency p50 2ms average 1.6 ms Latency p99 3ms max 9 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **47,562** · 2 : **48,398** req/s · spread 1.7 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.2 vCPU**, **140 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **839 MB** · Redis **0.3 vCPU** · whole server busy **87 %**, of which kernel (network, disk) **31 %** · memory used **1819 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 47,888 711,782 requests in 15 s Latency p50 2ms average 1.6 ms Latency p99 3ms max 9 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **47,455** · 2 : **48,321** req/s · spread 1.8 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.2 vCPU**, **135 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **798 MB** · Redis **0.3 vCPU** · whole server busy **87 %**, of which kernel (network, disk) **31 %** · memory used **2284 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · get by id with caching, public · round 1 of 2, the closer to the average **MySQL** Requests / second 48,818 731,797 requests in 15 s Latency p50 2ms average 1.5 ms Latency p99 3ms max 12 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **48,784** · 2 : **48,852** req/s · spread 0.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.2 vCPU**, **134 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **864 MB** · Redis **0.3 vCPU** · whole server busy **87 %**, of which kernel (network, disk) **31 %** · memory used **2551 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, public · round 1 of 2, the closer to the average ### Get by id with caching : both tokens With `x-am-authorization` and `x-am-user-authorization`, both checked on every request. Each answer : 278 bytes (MongoDB), status 200. **MongoDB** Requests / second 38,521 582,318 requests in 15 s Latency p50 2ms average 2.1 ms Latency p99 4ms max 15 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **38,824** · 2 : **38,218** req/s · spread 1.6 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.5 vCPU**, **139 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **839 MB** · Redis **0.3 vCPU** · whole server busy **89 %**, of which kernel (network, disk) **25 %** · memory used **1799 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · get by id with caching, both tokens · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 38,045 574,818 requests in 15 s Latency p50 2ms average 2.1 ms Latency p99 4ms max 14 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **38,320** · 2 : **37,770** req/s · spread 1.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.4 vCPU**, **136 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **798 MB** · Redis **0.3 vCPU** · whole server busy **88 %**, of which kernel (network, disk) **26 %** · memory used **2279 MB** of 15992 MB · steal **1 %** · swap not touched autocannon · PostgreSQL · get by id with caching, both tokens · round 1 of 2, the closer to the average **MySQL** Requests / second 38,544 579,232 requests in 15 s Latency p50 2ms average 2.1 ms Latency p99 4ms max 11 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **38,617** · 2 : **38,472** req/s · spread 0.4 % · the output below is round 1, the closer to the average (Server during this run) API Maker **6.5 vCPU**, **134 MB** RSS · MongoDB **0.0 vCPU** · MySQL **0.0 vCPU** · sandboxes **0.0 vCPU**, **864 MB** · Redis **0.2 vCPU** · whole server busy **89 %**, of which kernel (network, disk) **27 %** · memory used **2545 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · get by id with caching, both tokens · round 1 of 2, the closer to the average ## Insert one row `POST …/
/save-single-or-multiple` with one row of 9 columns in the body : the schema checks and converts it, the database writes it, and the saved row is answered. [About this API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html). No token : the API is public. Each answer : 277 bytes (MongoDB), status 201. **MongoDB** Requests / second 5,490 82,779 requests in 15 s Latency p50 17ms average 17.6 ms Latency p99 32ms max 63 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,519** · 2 : **5,460** req/s · spread 1.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.3 vCPU**, **145 MB** RSS · MongoDB **3.7 vCPU** · sandboxes **0.0 vCPU**, **839 MB** · whole server busy **88 %**, of which kernel (network, disk) **25 %** · memory used **1919 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MongoDB · insert one row, public · round 1 of 2, the closer to the average **PostgreSQL** Requests / second 5,874 88,216 requests in 15 s Latency p50 16ms average 16.5 ms Latency p99 19ms max 35 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **5,882** · 2 : **5,867** req/s · spread 0.3 % · the output below is round 1, the closer to the average (Server during this run) API Maker **2.0 vCPU**, **140 MB** RSS · MongoDB **0.0 vCPU** · PostgreSQL **2.2 vCPU** · sandboxes **0.0 vCPU**, **798 MB** · whole server busy **68 %**, of which kernel (network, disk) **24 %** · memory used **2294 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · PostgreSQL · insert one row, public · round 1 of 2, the closer to the average **MySQL** Requests / second 3,542 52,989 requests in 15 s Latency p50 28ms average 27.8 ms Latency p99 38ms max 51 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **3,551** · 2 : **3,533** req/s · spread 0.5 % · the output below is round 2, the closer to the average (Server during this run) API Maker **1.3 vCPU**, **139 MB** RSS · MongoDB **0.0 vCPU** · MySQL **3.2 vCPU** · sandboxes **0.0 vCPU**, **864 MB** · whole server busy **73 %**, of which kernel (network, disk) **20 %** · memory used **2551 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · MySQL · insert one row, public · round 2 of 2, the closer to the average ## Custom API without a database A public custom API whose code returns a small object and reads no database : what running code of the account costs, without a database. Lean code runs in the server itself, with QuickJS ; the same code with `Date.now()` in it runs in a sandbox of the account : the trip from API Maker to the runner in its container and back. **In the server (lean code)** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from API Maker', time: 1 }; } module.exports = main; ``` Requests / second 39,192 581,838 requests in 15 s Latency p50 2ms average 2.1 ms Latency p99 4ms max 12 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **38,789** · 2 : **39,594** req/s · spread 2.1 % · the output below is round 1, the closer to the average (Server during this run) API Maker **7.8 vCPU**, **136 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU**, **847 MB** · whole server busy **98 %**, of which kernel (network, disk) **24 %** · memory used **2035 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the server (lean code) · round 1 of 2, the closer to the average **In the sandbox** **The custom API** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { return { message: 'Hello from the sandbox', time: Date.now() }; } module.exports = main; ``` Requests / second 27,920 419,242 requests in 15 s Latency p50 3ms average 3.1 ms Latency p99 8ms max 211 ms Errors 0 non-2xx, errors, timeouts (2 rounds of 15 s) 1 : **27,949** · 2 : **27,891** req/s · spread 0.2 % · the output below is round 1, the closer to the average (Server during this run) API Maker **5.1 vCPU**, **139 MB** RSS · MongoDB **0.0 vCPU** · sandboxes **2.4 vCPU**, **851 MB** · whole server busy **94 %**, of which kernel (network, disk) **27 %** · memory used **2053 MB** of 15992 MB · steal **0 %** · swap not touched autocannon · custom API without a database, in the sandbox · round 1 of 2, the closer to the average ## More connections *Get all, public* and *Get by id with caching, public* on MongoDB, one run of 15 seconds for each number of connections. More clients at once wait longer for their answer, and the server keeps answering them all. ### Get all, public, by connections **Get all, public, MongoDB : requests per second by connections** 10 connectionsp50 1 ms · p99 2 ms · 8,465 50 connectionsp50 3 ms · p99 9 ms · 11,967 100 connectionsp50 7 ms · p99 17 ms · 12,429 250 connectionsp50 19 ms · p99 31 ms · 12,311 500 connectionsp50 41 ms · p99 52 ms · 11,995 1,000 connectionsp50 84 ms · p99 95 ms · 11,850 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **8,465** | 1 ms | 2 ms | 7 ms | 0 | 66 % | 136 MB | | 50 | **11,967** | 3 ms | 9 ms | 27 ms | 0 | 91 % | 140 MB | | 100 | **12,429** | 7 ms | 17 ms | 52 ms | 0 | 95 % | 145 MB | | 250 | **12,311** | 19 ms | 31 ms | 63 ms | 0 | 95 % | 155 MB | | 500 | **11,995** | 41 ms | 52 ms | 78 ms | 0 | 95 % | 171 MB | | 1,000 | **11,850** | 84 ms | 95 ms | 121 ms | 0 | 95 % | 204 MB | ### Get by id with caching, public, by connections **Get by id with caching, public, MongoDB : requests per second by connections** 10 connectionsp50 0 ms · p99 0 ms · 17,269 50 connectionsp50 1 ms · p99 2 ms · 42,288 100 connectionsp50 2 ms · p99 3 ms · 47,361 250 connectionsp50 5 ms · p99 8 ms · 48,716 500 connectionsp50 10 ms · p99 14 ms · 49,704 1,000 connectionsp50 20 ms · p99 27 ms · 49,008 | Connections | Requests / second | p50 | p99 | Max | Errors | Server busy | API Maker RSS | |--:|--:|--:|--:|--:|--:|--:|--:| | 10 | **17,269** | 0 ms | 0 ms | 4 ms | 0 | 48 % | 140 MB | | 50 | **42,288** | 1 ms | 2 ms | 12 ms | 0 | 85 % | 140 MB | | 100 | **47,361** | 2 ms | 3 ms | 11 ms | 0 | 87 % | 144 MB | | 250 | **48,716** | 5 ms | 8 ms | 17 ms | 0 | 89 % | 155 MB | | 500 | **49,704** | 10 ms | 14 ms | 34 ms | 0 | 90 % | 166 MB | | 1,000 | **49,008** | 20 ms | 27 ms | 241 ms | 0 | 89 % | 194 MB | ## Questions ### How many requests per second can API Maker serve on 8 dedicated vCPUs ? On this 16 GB server, with the database on the same machine : 12,640 requests per second for a whole table of ten rows on MongoDB (PostgreSQL 12,641 · MySQL 13,748), 14,224 for one row by its id, and 47,980 when the answer is cached in Redis. A custom API in TypeScript which reads the table answers 8,893 requests per second when API Maker runs it itself (lean code), 7,569 when it runs in the sandbox of the account. ### How much memory does API Maker use ? The API Maker process held 111 MB at rest and 176 MB at most under load on this server, in RAM. The rest of the memory went to the databases (MongoDB, Redis, PostgreSQL or MySQL), the sandboxes which run the code of the account, and Linux itself. ### Do the two tokens slow the APIs down ? API Maker checks both tokens (x-am-authorization and x-am-user-authorization) and the groups of the API user on every request. Get all with both tokens answered 12,106 requests per second on MongoDB (public : 12,640), 11,913 requests per second on PostgreSQL (public : 12,641), 12,712 requests per second on MySQL (public : 13,748). The checks show most where the database does no work : a cached get all answered 36,123 requests per second with both tokens against 43,980 public on MongoDB. ### What does a pre hook cost ? A pre hook runs code of the account before the API ; a lean hook like this one runs in the server itself, with QuickJS. Get all with a row scoping pre hook answered 9,279 requests per second on MongoDB, against 12,106 for the same API without the hook. On 8 vCPUs, the API, the hook and the database share the same 8 vCPUs. ### Can I run these benchmarks myself ? Yes : [How API Maker is benchmarked](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html) gives the dataset, the settings of every API and the exact autocannon commands. --- # API Maker WebSocket benchmarks : connections per server, memory per client, scaling > API Maker WebSocket benchmarks on 7 Linode servers : up to 3.66 million clients on one server, 8.5 to 8.8 KB per client, new clients and notifications a second, and how to scale. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/index.html WebSocket benchmarks · API Maker 4.0.0 · 7 servers and 3 clusters · measured 14 October 2026 **How many WebSocket users can API Maker hold ? As many as the memory has room for.** API Maker installed by its own installer on 7 Linode servers, from 1 to 8 vCPUs, its MongoDB and Redis on the same machine. A second server opened WebSocket clients, each with both tokens and a subscription of its own, until the server was full, and autocannon made the calls which notify them, 60 seconds a run : 50,167,783 clients let in, 214,875,630 notifications delivered. Every page shows the outputs and what each part of the server held in memory. Clients on one server · 8 vCPU, 32 GB 3,662,564 connected at once · 1 vCPU, 1 GB : 26,484 Memory per client 8.5 to 8.8KB API Maker, the kernel and Redis together New clients / second · 8 vCPU 10,939 both tokens and a subscription · 1 vCPU : 2,602 Notification delivered in 0.83ms p50, from the HTTP call to the client ## The answers - [How many connections can one server hold ?](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/index.html#one-server) : 26,484 on 1 vCPU and 1 GB, 3,662,564 on 8 vCPUs and 32 GB. Memory ends first, never the CPU. - [How much memory when a server is full ?](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/index.html#memory) : 8.5 to 8.8 KB per client in all. Every part of each server, with every client connected. - [How do we scale to N users ?](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/index.html#scale) : More servers behind a load balancer, one Redis they share. The picture, and the rule to count the servers. - [One big server or several small ones ?](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/index.html#big-or-small) : The same 8 vCPUs and 16 GB as one, two and four servers, measured : 2.02M, 1.92M, 1.62M clients. - [What does the architecture look like ?](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#architecture) : The clients, a load balancer, API Maker servers which each hold their own clients, and the one Redis they share : the diagram, with what was measured. - [What happens when a server restarts ?](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html#restart) : 601,479 clients were all back after 189 s, in the memory they had before. When they all leave at once, their sockets are closed after 18.0 s. ## How many connections one server holds **WebSocket clients connected at once** · Shared CPU · Dedicated CPU [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html) · shared · $5 / month · 26,484 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html) · shared · $24 / month · 338,016 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html) · shared · $48 / month · 801,972 [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html) · shared · $192 / month · 3,662,564 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html) · dedicated · $36 / month · 338,006 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html) · dedicated · $72 / month · 795,888 [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html) · dedicated · $144 / month · 1,732,035 Each client connected with both tokens and one subscription of its own, MongoDB, Redis and two sandboxes on the same server. | Server | CPU · price / month | Clients connected | What ended first | API Maker | Whole server, used | Per client | Clients per $ a month | |---|---|--:|---|--:|--:|--:|--:| | [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html) | Shared · $5 | **26,484** | memory | 126 MB | 813 MB of 961 MB | 8.6 KB | 5,297 | | [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html) | Shared · $24 | **338,016** | memory | 1,110 MB | 3,417 MB of 3,916 MB | 8.5 KB | 14,084 | | [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html) | Shared · $48 | **801,972** | memory | 2,495 MB | 6,937 MB of 7,941 MB | 8.7 KB | 16,708 | | [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html) | Shared · $192 | **3,662,564** | memory | 10,196 MB | 27,618 MB of 32,096 MB | 8.8 KB | 19,076 | | [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html) | Dedicated · $36 | **338,006** | memory | 1,108 MB | 3,465 MB of 3,916 MB | 8.5 KB | 9,389 | | [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html) | Dedicated · $72 | **795,888** | memory | 2,474 MB | 6,917 MB of 7,941 MB | 8.7 KB | 11,054 | | [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html) | Dedicated · $144 | **1,732,035** | memory | 5,179 MB | 13,942 MB of 15,992 MB | 8.8 KB | 12,028 | A client which waits costs memory, and almost no CPU : the server pings it once a minute. So the number of clients a server holds follows its memory, shared or dedicated CPU alike. The page of each server gives every level of clients on the way, with what each part held. ## Memory when a server is full API Maker · MongoDB of API Maker · Redis · Sandboxes · Linux : its sockets, Docker, the rest · Available [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#memory-at-full) 26k clients [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#memory-at-full) 338k clients [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#memory-at-full) 802k clients [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#memory-at-full) 3.66M clients [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#memory-at-full) 338k clients [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#memory-at-full) 796k clients [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#memory-at-full) 1.73M clients | Server | Clients | API Maker | Redis | Linux kernel | Per client : API Maker · kernel · Redis | Per client, in all | |---|--:|--:|--:|--:|--:|--:| | [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#memory-at-full) | 26,484 | **126 MB** | 30 MB | 200 MB | 3.3 · 4.3 · 1.0 KB | **8.6 KB** | | [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#memory-at-full) | 338,016 | **1,110 MB** | 356 MB | 1,635 MB | 3.1 · 4.3 · 1.0 KB | **8.5 KB** | | [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#memory-at-full) | 801,972 | **2,495 MB** | 808 MB | 3,715 MB | 3.3 · 4.4 · 1.1 KB | **8.7 KB** | | [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#memory-at-full) | 3,662,564 | **10,196 MB** | 3,533 MB | 16,443 MB | 3.2 · 4.5 · 1.1 KB | **8.8 KB** | | [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#memory-at-full) | 338,006 | **1,108 MB** | 356 MB | 1,627 MB | 3.1 · 4.3 · 1.0 KB | **8.5 KB** | | [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#memory-at-full) | 795,888 | **2,474 MB** | 802 MB | 3,691 MB | 3.3 · 4.4 · 1.1 KB | **8.7 KB** | | [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#memory-at-full) | 1,732,035 | **5,179 MB** | 1,633 MB | 7,839 MB | 3.2 · 4.5 · 1.1 KB | **8.8 KB** | ## Scale to N users > Diagram : N WebSocket users : a load balancer, API Maker servers which each hold their clients, one Redis they share > > How API Maker serves N WebSocket users : the clients keep a WebSocket open to a load balancer, which passes each one to an API Maker server ; every server holds the clients which reached it, about 8 to 9 KB each ; all the servers share one Redis, which keeps a key and a channel per subscription and carries every notification to the server which holds the client, and one MongoDB. More users : more servers. A WebSocket stays on the server it reached, and what is said to a client can come from any server : the server which answers an API call, or runs `emitEventWS`, publishes the notification in Redis, and the server which holds the client sends it. So more users are more servers, and nothing else : no sticky session, no broker to add. How it was measured, and what ends first : [Scale to N users](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html). ## One big server or several small ones The same 8 dedicated vCPUs and 16 GB for API Maker, at the same price, as one server, two, and four ; MongoDB and Redis on a server of their own each time. | | [1 × 8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-1x8) | [2 × 4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-2x4) | [4 × 2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-4x2) | |---|--:|--:|--:| | Clients connected at once | **2,022,026** | **1,915,960** | **1,619,372** | | … on each server | 2,022,026 | 957,980 | 404,843 | | Memory per client, in all | 8.8 KB | 8.8 KB | 8.6 KB | | New clients a second (both tokens, a subscription) | **12,412** | **12,696** | **10,297** | | … connect only, both tokens | 19,917 | 21,417 | 17,882 | | A notification for one person : delivery p50 | 1.01 ms | 1.18 ms | 1.37 ms | | … p99 | 1.72 ms | 1.80 ms | 2.51 ms | | Notifications a second, one person each | 24,305 | 24,977 | 25,566 | | Notifications a second, broadcast | 217,711 | 228,910 | 272,609 | | One server stops : clients dropped | 1,516,519 of 1,516,519 (100 %) | 383,192 of 766,384 (50 %) | 242,906 of 971,623 (25 %) | | … all back after | 221 s | 68.0 s | 38.0 s | Several servers hold about what one big server holds, and lose only their share of the clients when one of them stops. [The whole comparison](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#big-or-small). ## New clients and notifications **New clients per second : both tokens and a subscription** · Shared CPU · Dedicated CPU [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html) · shared · $5 / month · 2,602 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html) · shared · $24 / month · 4,041 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html) · shared · $48 / month · 7,009 [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html) · shared · $192 / month · 10,939 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html) · dedicated · $36 / month · 3,464 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html) · dedicated · $72 / month · 6,627 [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html) · dedicated · $144 / month · 10,093 100 clients at a time connect, subscribe and leave, for 60 seconds. **Notifications per second : a broadcast to 1,000 clients** · Shared CPU · Dedicated CPU [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html) · shared · $5 / month · 72,245 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html) · shared · $24 / month · 103,387 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html) · shared · $48 / month · 147,974 [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html) · shared · $192 / month · 196,995 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html) · dedicated · $36 / month · 69,874 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html) · dedicated · $72 / month · 117,698 [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html) · dedicated · $144 / month · 206,570 autocannon calls the emit event WS API as fast as the server takes ; what the clients received each second. ## The servers ### Shared CPU - [1 vCPU · 1 GB RAM · Shared CPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html) : Linode Nanode 1 GB, $5 a month. 26,484 clients connected at once, 8.6 KB each. 2,602 new clients a second, a notification delivered in 2.51 ms. (14 October 2026 · 1,178,093 clients let in, 8,974,494 notifications) - [2 vCPU · 4 GB RAM · Shared CPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html) : Linode 4 GB, $24 a month. 338,016 clients connected at once, 8.5 KB each. 4,041 new clients a second, a notification delivered in 1.45 ms. (14 October 2026 · 2,479,554 clients let in, 12,715,952 notifications) - [4 vCPU · 8 GB RAM · Shared CPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html) : Linode 8 GB, $48 a month. 801,972 clients connected at once, 8.7 KB each. 7,009 new clients a second, a notification delivered in 1.06 ms. (14 October 2026 · 4,344,936 clients let in, 18,566,111 notifications) - [8 vCPU · 32 GB RAM · Shared CPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html) : Linode 32 GB, $192 a month. 3,662,564 clients connected at once, 8.8 KB each. 10,939 new clients a second, a notification delivered in 0.94 ms. (14 October 2026 · 8,562,774 clients let in, 22,866,139 notifications) ### Dedicated CPU - [2 vCPU · 4 GB RAM · Dedicated CPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html) : Linode Dedicated 4 GB, $36 a month. 338,006 clients connected at once, 8.5 KB each. 3,464 new clients a second, a notification delivered in 1.74 ms. (14 October 2026 · 2,080,093 clients let in, 9,736,661 notifications) - [4 vCPU · 8 GB RAM · Dedicated CPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html) : Linode Dedicated 8 GB, $72 a month. 795,888 clients connected at once, 8.7 KB each. 6,627 new clients a second, a notification delivered in 1.04 ms. (14 October 2026 · 4,102,260 clients let in, 15,486,511 notifications) - [8 vCPU · 16 GB RAM · Dedicated CPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html) : Linode Dedicated 16 GB, $144 a month. 1,732,035 clients connected at once, 8.8 KB each. 10,093 new clients a second, a notification delivered in 0.83 ms. (14 October 2026 · 6,038,773 clients let in, 23,621,794 notifications) ## How it is measured 1. **A real installation** API Maker is installed by its [installer](https://docs.apimaker.dev/v4/docs/getting-started/install-on-server.html) with its default answers, MongoDB and Redis in Docker on the same server. Nothing else runs : no reverse proxy, no other database. 2. **Real clients, from a second server** A dedicated server of the same data centre opens the WebSocket clients, from 11 addresses of its own (one address reaches one port of a server about 64,000 times). A client connects with both tokens, is told `CONNECTED`, sends one `REGISTER` with a condition of its own, and answers the pings of the server. 3. **autocannon makes the HTTP calls** The calls which notify the clients (the emit event WS API, the insert API of a table) and get all are made by autocannon, as in the API benchmarks. The clients count what they are told, and how late. 4. **60 seconds a run** Every measured run lasts 60 seconds, after a warm-up. Clients which were refused, notifications which did not arrive and calls which failed are counted. 5. **Clients are added until the server is full** Level after level, each held 30 seconds while the server is sampled (the last one 60). The run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server, or when it lets nobody else in : the clients fit in memory, not in the swap. 6. **Memory and CPU every second** The server samples its memory, its CPU, the API Maker process, every container, the sockets of the kernel and the table of its firewall while the clients are there. The whole method, the events, the can user connect codes and the commands : [How the WebSocket benchmarks are made](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html). The data is the [API Maker benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`). The APIs themselves : [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/index.html). ## Questions ### How many WebSocket connections can one API Maker server hold ? As many as its memory has room for : 26,484 on 1 shared vCPU and 1 GB, 338,016 on 2 shared vCPUs and 4 GB, 801,972 on 4 shared vCPUs and 8 GB, 3,662,564 on 8 shared vCPUs and 32 GB, 338,006 on 2 dedicated vCPUs and 4 GB, 795,888 on 4 dedicated vCPUs and 8 GB, 1,732,035 on 8 dedicated vCPUs and 16 GB, with MongoDB, Redis and two sandboxes on the same machine. A client which waits costs 8.5 to 8.8 KB of the server in all, and almost no CPU. ### How much memory does a WebSocket connection use ? 8.5 to 8.8 KB in all on the servers measured, for a client connected with both tokens and one subscription : most of it in the API Maker process, the rest in the Linux kernel (the socket) and in Redis (the subscription). ### How do I scale to N WebSocket users ? Add API Maker servers behind a load balancer : each holds the clients which reached it, and they share one Redis, which carries every notification to the server which holds the client. Count the servers from the memory : N users × 8.5 to 8.8 KB, plus one spare server. Measured : 1,915,960 clients on 2 servers, 1,619,372 on 4 servers. See [Scale to N users](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html). ### One big server or several small ones ? For the same price, they hold about the same number of clients : 2,022,026 on 1 × 8 vCPU · 16 GB, 1,915,960 on 2 × 4 vCPU · 8 GB, 1,619,372 on 4 × 2 vCPU · 4 GB. Several servers lose only a part of the clients when one of them stops, and can be restarted one at a time ; one big server has less to run. See [Scale to N users](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html). ### How fast are WebSocket notifications ? A notification for one person reached its client in 0.8 to 2.5 ms (p50) from the HTTP call which emitted it, at 1,000 notifications a second. In a broadcast, a server told up to 206,570 clients a second. --- # API Maker WebSocket benchmarks : all results, every server side by side > Every WebSocket result of API Maker on 7 Linode servers side by side : clients connected, memory per client, new clients and notifications a second, delivery times. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html WebSocket benchmarks · All results · API Maker 4.0.0 · 14 October 2026 **Every WebSocket result, side by side.** 7 Linode servers, from 1 to 8 vCPUs, shared and dedicated CPU, API Maker with its MongoDB and Redis on the same machine, and 3 clusters of API servers which share one Redis. 50,167,783 clients let in, 214,875,630 notifications delivered, 28,019,607 HTTP calls, 0 failures. Each number links to its run, with the output. Most clients on one server 3,662,564 8 shared vCPUs, 32 GB Memory per client 8.5 to 8.8KB 118,483 to 123,507 clients per GB New clients / second 2,602 to 10,939 both tokens and a subscription Delivery p50 0.83 to 2.51ms a notification for one person ## Clients connected at once **WebSocket clients connected at once** · Shared CPU · Dedicated CPU [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html) · shared · $5 / month · 26,484 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html) · shared · $24 / month · 338,016 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html) · shared · $48 / month · 801,972 [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html) · shared · $192 / month · 3,662,564 [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html) · dedicated · $36 / month · 338,006 [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html) · dedicated · $72 / month · 795,888 [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html) · dedicated · $144 / month · 1,732,035 | Server | CPU · price / month | Clients connected | What ended first | API Maker | Whole server, used | Per client | Clients per $ a month | |---|---|--:|---|--:|--:|--:|--:| | [1 vCPU · 1 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html) | Shared · $5 | **26,484** | memory | 126 MB | 813 MB of 961 MB | 8.6 KB | 5,297 | | [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html) | Shared · $24 | **338,016** | memory | 1,110 MB | 3,417 MB of 3,916 MB | 8.5 KB | 14,084 | | [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html) | Shared · $48 | **801,972** | memory | 2,495 MB | 6,937 MB of 7,941 MB | 8.7 KB | 16,708 | | [8 vCPU · 32 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html) | Shared · $192 | **3,662,564** | memory | 10,196 MB | 27,618 MB of 32,096 MB | 8.8 KB | 19,076 | | [2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html) | Dedicated · $36 | **338,006** | memory | 1,108 MB | 3,465 MB of 3,916 MB | 8.5 KB | 9,389 | | [4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html) | Dedicated · $72 | **795,888** | memory | 2,474 MB | 6,917 MB of 7,941 MB | 8.7 KB | 11,054 | | [8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html) | Dedicated · $144 | **1,732,035** | memory | 5,179 MB | 13,942 MB of 15,992 MB | 8.8 KB | 12,028 | ## Memory | With every client connected | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | Clients | [**26,484**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#capacity) | [**338,016**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#capacity) | [**801,972**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#capacity) | [**3,662,564**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#capacity) | [**338,006**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#capacity) | [**795,888**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#capacity) | [**1,732,035**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#capacity) | | API Maker (process) | [126 MB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#memory-at-full) | [1,110 MB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#memory-at-full) | [2,495 MB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#memory-at-full) | [10,196 MB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#memory-at-full) | [1,108 MB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#memory-at-full) | [2,474 MB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#memory-at-full) | [5,179 MB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#memory-at-full) | | Redis | 30 MB | 356 MB | 808 MB | 3,533 MB | 356 MB | 802 MB | 1,633 MB | | Linux kernel (slab) | 200 MB | 1,635 MB | 3,715 MB | 16,443 MB | 1,627 MB | 3,691 MB | 7,839 MB | | MongoDB of API Maker | 110 MB | 117 MB | 64 MB | 61 MB | 125 MB | 66 MB | 52 MB | | Sandboxes | 143 MB | 91 MB | 206 MB | 245 MB | 99 MB | 203 MB | 334 MB | | Whole server, used | **813 MB** | **3,417 MB** | **6,937 MB** | **27,618 MB** | **3,465 MB** | **6,917 MB** | **13,942 MB** | | Available | 149 MB | 499 MB | 1,005 MB | 4,478 MB | 451 MB | 1,024 MB | 2,050 MB | | Swap used | 176 MB | 310 MB | 609 MB | 2,691 MB | 270 MB | 594 MB | 1,525 MB | | API Maker at rest, no client | 103 MB | 110 MB | 118 MB | 121 MB | 109 MB | 118 MB | 117 MB | | Per client : API Maker | [3.3 KB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#per-client) | [3.1 KB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#per-client) | [3.3 KB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#per-client) | [3.2 KB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#per-client) | [3.1 KB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#per-client) | [3.3 KB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#per-client) | [3.2 KB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#per-client) | | Per client : Linux kernel | 4.3 KB | 4.3 KB | 4.4 KB | 4.5 KB | 4.3 KB | 4.4 KB | 4.5 KB | | Per client : Redis | 1.0 KB | 1.0 KB | 1.1 KB | 1.1 KB | 1.0 KB | 1.1 KB | 1.1 KB | | Per client : in all | **8.6 KB** | **8.5 KB** | **8.7 KB** | **8.8 KB** | **8.5 KB** | **8.7 KB** | **8.8 KB** | | Clients per GB | 121,927 | 123,507 | 120,250 | 118,483 | 123,507 | 120,250 | 118,886 | ## New clients per second | 100 clients at a time | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | Connect : the token of the API user | [**5,905**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#connect-1-token) | [**9,799**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#connect-1-token) | [**15,228**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#connect-1-token) | [**24,511**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#connect-1-token) | [**7,417**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#connect-1-token) | [**13,849**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#connect-1-token) | [**21,780**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#connect-1-token) | | Connect : both tokens | [**5,302**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#connect-2-tokens) | [**9,504**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#connect-2-tokens) | [**12,826**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#connect-2-tokens) | [**24,719**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#connect-2-tokens) | [**7,077**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#connect-2-tokens) | [**12,535**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#connect-2-tokens) | [**19,391**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#connect-2-tokens) | | Connect with both tokens and subscribe | [**2,602**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#subscribe) | [**4,041**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#subscribe) | [**7,009**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#subscribe) | [**10,939**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#subscribe) | [**3,464**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#subscribe) | [**6,627**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#subscribe) | [**10,093**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#subscribe) | | Subscribe to an event with a can user connect code | [**2,097**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#can-user-connect) | [**3,438**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#can-user-connect) | [**5,916**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#can-user-connect) | [**9,280**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#can-user-connect) | [**2,891**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#can-user-connect) | [**5,533**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#can-user-connect) | [**8,963**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#can-user-connect) | | Subscribe : the code reads the database | [**959**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#can-user-connect-database) | [**1,605**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#can-user-connect-database) | [**2,735**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#can-user-connect-database) | [**4,381**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#can-user-connect-database) | [**1,368**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#can-user-connect-database) | [**2,046**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#can-user-connect-database) | [**3,919**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#can-user-connect-database) | | Subscribe : the code reads the clock | [**1,960**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#can-user-connect-sandbox) | [**3,031**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#can-user-connect-sandbox) | [**5,243**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#can-user-connect-sandbox) | [**7,741**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#can-user-connect-sandbox) | [**2,550**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#can-user-connect-sandbox) | [**4,505**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#can-user-connect-sandbox) | [**7,543**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#can-user-connect-sandbox) | | Subscribed after, p50 | 33.2 ms | 21.5 ms | 12.5 ms | 7.91 ms | 25.1 ms | 13.4 ms | 8.85 ms | | Subscribed after, p99 | 47.5 ms | 31.2 ms | 18.9 ms | 13.4 ms | 35.0 ms | 19.3 ms | 12.8 ms | ## Notifications | How late : at a pace | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | A notification for one person : delivery p50 | [**2.51 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#one-person) | [**1.45 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#one-person) | [**1.06 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#one-person) | [**0.94 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#one-person) | [**1.74 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#one-person) | [**1.04 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#one-person) | [**0.83 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#one-person) | | … p99 | 3.82 ms | 3.15 ms | 2.03 ms | 6.54 ms | 3.70 ms | 2.03 ms | 1.27 ms | | A broadcast : delivery p50 | [**10.3 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#broadcast) | [**8.82 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#broadcast) | [**7.56 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#broadcast) | [**8.70 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#broadcast) | [**10.3 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#broadcast) | [**8.00 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#broadcast) | [**6.53 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#broadcast) | | … p99 | 21.6 ms | 18.0 ms | 16.4 ms | 19.9 ms | 18.3 ms | 17.3 ms | 14.0 ms | | Rows inserted in a table : delivery p50 | [**51.3 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#insert) | [**25.3 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#insert) | [**18.1 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#insert) | [**13.4 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#insert) | [**35.1 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#insert) | [**20.7 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#insert) | [**12.9 ms**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#insert) | | … p99 | 103 ms | 44.4 ms | 30.0 ms | 35.5 ms | 54.8 ms | 34.5 ms | 19.8 ms | | How many : notifications a second | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | A notification for one person | [**5,216**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#one-person) | [**7,562**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#one-person) | [**13,441**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#one-person) | [**21,208**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#one-person) | [**6,618**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#one-person) | [**12,791**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#one-person) | [**21,001**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#one-person) | | … HTTP calls a second | 5,285 | 7,657 | 13,711 | 21,628 | 6,757 | 13,049 | 21,252 | | A broadcast | [**72,245**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#broadcast) | [**103,387**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#broadcast) | [**147,974**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#broadcast) | [**196,995**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#broadcast) | [**69,874**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#broadcast) | [**117,698**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#broadcast) | [**206,570**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#broadcast) | | … HTTP calls a second | 73 | 105 | 150 | 199 | 71 | 120 | 209 | | Rows inserted in a table | [**40,498**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#insert) | [**59,275**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#insert) | [**92,279**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#insert) | [**136,942**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#insert) | [**49,312**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#insert) | [**76,505**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#insert) | [**132,499**](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#insert) | | … HTTP calls a second | 416 | 604 | 932 | 1,396 | 506 | 779 | 1,350 | ## With every client connected | | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | Clients connected | [26,484](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#full) | [338,016](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#full) | [801,972](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#full) | [3,662,564](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#full) | [338,006](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#full) | [795,888](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#full) | [1,732,035](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#full) | | A notification for one person : delivery p50 | **2.49 ms** | **1.47 ms** | **1.22 ms** | **1.28 ms** | **1.76 ms** | **1.03 ms** | **0.87 ms** | | … p99 | 7.48 ms | 3.27 ms | 2.44 ms | 121 ms | 3.03 ms | 1.99 ms | 1.47 ms | | Notifications a second, one person each | 5,226 | 6,967 | 10,799 | 8,384 | 5,705 | 9,745 | 15,938 | | Get all with both tokens, no client : req/s | 2,095 | 3,379 | 6,072 | 9,529 | 3,058 | 5,268 | 9,672 | | Get all with both tokens, every client connected : req/s | **1,983** | **3,006** | **4,767** | **3,997** | **2,614** | **4,185** | **7,305** | ## A restart | API Maker restarts | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html)
shared · 1 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html)
shared · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html)
shared · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html)
shared · 32 GB | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html)
dedicated · 4 GB | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html)
dedicated · 8 GB | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html)
dedicated · 16 GB | |---|--:|--:|--:|--:|--:|--:|--:| | Clients connected | [19,863](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#restart) | [253,512](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#restart) | [601,479](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#restart) | – | [253,504](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#restart) | [596,916](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#restart) | – | | All back after | **10.0 s** | **90.0 s** | **189 s** | – | **159 s** | **189 s** | – | | A client was away, p50 | 7.4 s | 48.9 s | 76.7 s | – | 68.7 s | 79.1 s | – | | A client was away, p99 | 9.1 s | 78.2 s | 173 s | – | 96.5 s | 172 s | – | | Every client leaves at once : sockets closed after | 1.5 s | 10.1 s | 18.0 s | – | 15.1 s | 23.4 s | – | | … Redis forgot them after | 2.6 s | 13.8 s | 26.9 s | – | 16.1 s | 29.1 s | – | ## Several servers The same 8 dedicated vCPUs and 16 GB for API Maker, as one server, two, and four, with MongoDB and Redis on a server of their own : [Scale to N users](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html). | | [1 × 8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-1x8) | [2 × 4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-2x4) | [4 × 2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-4x2) | |---|--:|--:|--:| | Clients connected at once | **2,022,026** | **1,915,960** | **1,619,372** | | … on each server | 2,022,026 | 957,980 | 404,843 | | Memory per client, in all | 8.8 KB | 8.8 KB | 8.6 KB | | New clients a second (both tokens, a subscription) | **12,412** | **12,696** | **10,297** | | … connect only, both tokens | 19,917 | 21,417 | 17,882 | | A notification for one person : delivery p50 | 1.01 ms | 1.18 ms | 1.37 ms | | … p99 | 1.72 ms | 1.80 ms | 2.51 ms | | Notifications a second, one person each | 24,305 | 24,977 | 25,566 | | Notifications a second, broadcast | 217,711 | 228,910 | 272,609 | | One server stops : clients dropped | 1,516,519 of 1,516,519 (100 %) | 383,192 of 766,384 (50 %) | 242,906 of 971,623 (25 %) | | … all back after | 221 s | 68.0 s | 38.0 s | ## The servers | | [1 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html) | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html) | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html) | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html) | [2 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html) | [4 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html) | [8 vCPU](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html) | |---|---|---|---|---|---|---|---| | Plan | Nanode 1 GB
g6-nanode-1 | Linode 4 GB
g6-standard-2 | Linode 8 GB
g6-standard-4 | Linode 32 GB
g6-standard-8 | Dedicated 4 GB
g6-dedicated-2 | Dedicated 8 GB
g6-dedicated-4 | Dedicated 16 GB
g6-dedicated-8 | | CPU | AMD EPYC 7642
shared cpu | AMD EPYC 7642
shared cpu | AMD EPYC 7642
shared cpu | AMD EPYC 7642
shared cpu | AMD EPYC 7642
dedicated cpu | AMD EPYC 7642
dedicated cpu | AMD EPYC 7642
dedicated cpu | | Memory | 1 GB | 4 GB | 8 GB | 32 GB | 4 GB | 8 GB | 16 GB | | Price / month | $5 | $24 | $48 | $192 | $36 | $72 | $144 | | Load generator | Dedicated 8 GB | Dedicated 8 GB | Dedicated 16 GB | Dedicated 64 GB | Dedicated 8 GB | Dedicated 16 GB | Dedicated 32 GB | | … busy at most | 66 % | 98 % | 91 % | 85 % | 98 % | 90 % | 84 % | How every number was taken : [How the WebSocket benchmarks are made](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html). The data : [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`). --- # Scale API Maker WebSockets to N users : one big server or several small ones > How API Maker serves N WebSocket users : servers behind a load balancer which share one Redis, the rule to count them, and one big server against several small ones, measured. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html WebSocket benchmarks · Scaling · API Maker 4.0.0 · 14 October 2026 **Scale WebSockets to N users : add servers, they share one Redis.** A WebSocket stays on the server it reached, and a notification can come from any server : Redis carries it to the one which holds the client. So N users are a matter of memory, spread over as many servers as it takes. Measured on 3 clusters of the same price : the same 8 dedicated vCPUs and 16 GB for API Maker as one server, two, and four, with MongoDB and Redis on a server of their own. Clients on 1 server 2,022,026 1 × 8 vCPU · 16 GB, one Redis Memory per client 8.5 to 8.8KB the whole of it : API Maker, the kernel, Redis Servers for N users N ÷ C + 1 C : the clients one server holds, by its memory One server of four stops 25 % of the clients dropped, back after 38.0 s ## The picture > Diagram : N WebSocket users : a load balancer, API Maker servers which each hold their clients, one Redis they share > > How API Maker serves N WebSocket users : the clients keep a WebSocket open to a load balancer, which passes each one to an API Maker server ; every server holds the clients which reached it, about 8 to 9 KB each ; all the servers share one Redis, which keeps a key and a channel per subscription and carries every notification to the server which holds the client, and one MongoDB. More users : more servers. - **The clients** connect to one address, `wss://ws.example.com`, with their tokens in the query string. - **A load balancer** ends TLS and hands each WebSocket to one API Maker server : Caddy (the installer writes its line), HAProxy, or the load balancer of your cloud. It needs no sticky session, a WebSocket stays on the server it reached. - **Each API Maker server** checks the tokens, keeps its clients and their subscriptions, and pings them. Its clients cost it memory, about 8.5 to 8.8 KB each, and almost no CPU while they wait. - **One Redis**, the internal Redis of API Maker, is shared by the servers : a key and a channel for every subscription. The server which answers an API call, or runs `emitEventWS`, publishes the notification there ; the server which holds the client hears it and sends it. - **MongoDB** keeps the accounts, the events and their can user connect code : read when a client subscribes, then kept by each server. ## Count the servers 1. **Memory.** Users connected at once × the memory of a client (8.5 to 8.8 KB with both tokens and one subscription ; more subscriptions cost a little more each). It is spread over the API servers ; Redis takes 1.0 to 1.1 KB of it per subscription. 2. **Servers.** That memory ÷ what one server has left once API Maker, its sandboxes and Linux have theirs : the [page of each server](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html#capacity) gives the clients it held. Add one server, so that the others can take the clients of one which stops. 3. **The rest follows.** New clients a second and notifications a second grow with the vCPUs : the [results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html#connect) of each server size say how many. | Users connected at once | Memory they take, in all | Servers of 16 GB (1,732,035 clients each) | Memory of Redis | |--:|--:|--:|--:| | **10,000** | 86 MB | 1 + 1 spare | 10 MB | | **100,000** | 861 MB | 1 + 1 spare | 104 MB | | **500,000** | 4.2 GB | 1 + 1 spare | 522 MB | | **1,000,000** | 8.4 GB | 1 + 1 spare | 1 GB | | **5,000,000** | 42.1 GB | 3 + 1 spare | 5.1 GB | The open files of the service and the table of the firewall follow the memory of the server (the installer, 256 for each MB) : the memory is what ends, on every server measured. ## One big server or several small ones The same 8 dedicated vCPUs and 16 GB of memory for API Maker, at the same price a month, as **one** server, **two**, and **four**. Each time, MongoDB and Redis run on a server of their own, the clients go to the API servers in turn, and autocannon calls every API server at once. **Clients connected at once, for the same price** [1 × 8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-1x8) · $144 / month · 2,022,026 [2 × 4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-2x4) · $144 / month · 1,915,960 [4 × 2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-4x2) · $144 / month · 1,619,372 **New clients per second : both tokens and a subscription** [1 × 8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-1x8) · $144 / month · 12,412 [2 × 4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-2x4) · $144 / month · 12,696 [4 × 2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-4x2) · $144 / month · 10,297 | | [1 × 8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-1x8) | [2 × 4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-2x4) | [4 × 2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-4x2) | |---|--:|--:|--:| | Clients connected at once | **2,022,026** | **1,915,960** | **1,619,372** | | … on each server | 2,022,026 | 957,980 | 404,843 | | Memory per client, in all | 8.8 KB | 8.8 KB | 8.6 KB | | New clients a second (both tokens, a subscription) | **12,412** | **12,696** | **10,297** | | … connect only, both tokens | 19,917 | 21,417 | 17,882 | | A notification for one person : delivery p50 | 1.01 ms | 1.18 ms | 1.37 ms | | … p99 | 1.72 ms | 1.80 ms | 2.51 ms | | Notifications a second, one person each | 24,305 | 24,977 | 25,566 | | Notifications a second, broadcast | 217,711 | 228,910 | 272,609 | | One server stops : clients dropped | 1,516,519 of 1,516,519 (100 %) | 383,192 of 766,384 (50 %) | 242,906 of 971,623 (25 %) | | … all back after | 221 s | 68.0 s | 38.0 s | - **They hold about the same.** Every server keeps some memory for itself (API Maker at rest, two sandboxes, Linux, Docker), so four small servers hold a little less than one big one. - **They let in about as many clients a second**, and tell as many : the work is the same, spread over the same vCPUs, and Redis does its part on its own server. - **A server which stops takes its share of the clients with it** : all of them on one big server, a quarter on four. The clients come back by themselves, in 68.0 s on 2 × 4 vCPU · 8 GB and 38.0 s on 4 × 2 vCPU · 4 GB ; on one server they wait for it to start again, 221 s in all. - **Several servers can be restarted one at a time** : a new version of API Maker, or of your code, without every client going away at once. **So : one server while everything fits on it, several as soon as the clients must not all drop together.** Keep the other servers under 75 % full with four of them (50 % with two) : they then have room for the clients of the one which stops. ## What ends first | Limit | Where | What it is | |---|---|---| | **Memory** | Each API server | 8.5 to 8.8 KB per client. The first limit on every server measured. | | Open files | Each API server | A client is one open file. The installer lets the service open as many as the firewall tracks connections, 256 for each MB of memory and 1,048,576 at the least (`LimitNOFILE`, and `fs.nr_open` with it) : API Maker keeps a few for itself, and a sixteenth of its connections (4,096 at the most) for the calls of the APIs : without them, a server whose clients held every connection would answer no API call for as long as they stay. One more client is answered `503`. | | Tracked connections | Each API server | Docker makes Linux track every connection, and Linux drops new ones once its table is full (`nf_conntrack: table full`). As Linux sets it up, the table holds 262,144 connections on 4 GB or more, and a closed connection stays in it two minutes : the installer gives it room for 256 connections per MB of memory (twice the clients the memory holds, for the ones which come back after a restart while their old connections are still in it), and API Maker says at its start when the table is what limits it. | | Memory of the network | Each API server | A socket which holds something unread, or something its client has not acknowledged yet, keeps a page of the memory Linux gives all its TCP connections together (`net.ipv4.tcp_mem` : about 9 % of the memory of the server, as Linux sets it up). Past it, Linux slows every connection of the server down, the ones to its databases too : it happens when every client of a full server does something in the same second (they all come back, they all leave, they are all told). API Maker raises that memory as its clients come, two pages for each connection and never more than a quarter of the memory of the server (`tcpMemoryPercent`), and closes a socket without waiting for anything else : 601,479 clients which left in the same second were closed after 18.0 s. | | Ports of a proxy | The load balancer | A proxy reaches one port of one server from one address about 64,000 times (28,000 as Linux sets it up). More clients per server behind a proxy need more addresses on the proxy, or a load balancer which passes the connections on without opening its own. | | Redis | The data server | One key and one channel per subscription, in memory ; one thread carries every notification. With 2,022,026 clients it held 2,010 MB. | | Tokens | Your application | A client is closed when its token runs out : give tokens different lifetimes, or the clients all come back in the same second. | ## The clusters, one by one ### 1 × 8 vCPU · 16 GB | | | |---|---| | API servers | 1 × Dedicated 16 GB (g6-dedicated-8) : 8 dedicated vCPUs and 16 GB each, $144 a month in all. API Maker and its two sandboxes on each, attached to the data server by the installer (`--secondary`) | | Data server | Dedicated 8 GB (g6-dedicated-4) : AMD EPYC 7642 48-Core Processor, 4 dedicated vCPUs (KVM). MongoDB 8.0.10 and Redis 7.0.5 of API Maker, in Docker ; its own API Maker stopped | | CPU | AMD EPYC 7642 48-Core Processor | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Network limits | as the installer sets them, on every API server : 4,093,696 connections tracked (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted, 4,093,696 open files. The memory of all its TCP connections together : raised by API Maker as the clients came, to 3.9 GB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) | | Load generator | Dedicated 32 GB (g6-dedicated-16) : AMD EPYC 7642 48-Core Processor, 16 dedicated vCPUs. The clients go to the API servers in turn, as a load balancer hands them out ; autocannon calls every API server at the same time | | Network | A VLAN of the same data centre, round trip 0.33 ms (ping) | | Date | 14 October 2026, 03:19 to 04:02 UTC | Clients connected 2,022,026 2,022,026 on each of 1 server Memory per client 8.8KB API Maker 3.2 · kernel 4.5 · Redis 1.1 New clients / second 12,412 both tokens and a subscription · 19,917 without one Notification delivered in 1.01ms p50 at 1,000 a second · p99 1.72 ms The run stopped adding clients at **2,022,026** : the memory of the server `api-1` was full. 2,116 MB of its 15,992 MB were still counted as available, and Linux had moved 1,317 MB to the swap since the clients began to connect, to make that room : 799 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server). > Diagram : Clients connected and memory used during the run > > The run of this server, second after second : the WebSocket clients connected, up to 2,022,026, and the memory the server used, up to 14,465 MB of 15,991 MB. | Clients connected | API Maker, all servers | Linux kernel, all servers | API servers, used | Least available on a server | Redis (its data) | Data server, used | CPU busy | |---|--:|--:|--:|--:|--:|--:|--:| | No client (at rest) | 127 MB | 184 MB | 792 MB | 15,200 MB | 1 MB | 713 MB | 0.3 % | | **10,000** clients | 166 MB | 328 MB | 1,816 MB | 14,176 MB | 12 MB | 704 MB | 1.8 % | | **100,000** clients | 451 MB | 634 MB | 2,359 MB | 13,632 MB | 103 MB | 896 MB | 0.9 % | | **200,000** clients | 764 MB | 1,080 MB | 3,029 MB | 12,963 MB | 204 MB | 1,009 MB | 1.9 % | | **400,000** clients | 1,408 MB | 1,971 MB | 4,428 MB | 11,564 MB | 404 MB | 1,204 MB | 3.8 % | | **600,000** clients | 2,062 MB | 2,856 MB | 5,810 MB | 10,182 MB | 625 MB | 1,448 MB | 5.7 % | | **800,000** clients | 2,666 MB | 3,745 MB | 7,166 MB | 8,826 MB | 810 MB | 1,620 MB | 7.8 % | | **1,000,000** clients | 3,344 MB | 4,634 MB | 8,561 MB | 7,431 MB | 995 MB | 1,812 MB | 9.8 % | | **1,200,000** clients | 3,954 MB | 5,524 MB | 9,903 MB | 6,089 MB | 1,249 MB | 2,064 MB | 12.1 % | | **1,400,000** clients | 4,562 MB | 6,412 MB | 11,349 MB | 4,643 MB | 1,430 MB | 2,265 MB | 14.5 % | | **1,600,000** clients | 5,167 MB | 7,293 MB | 12,658 MB | 3,334 MB | 1,619 MB | 2,479 MB | 16.7 % | | **1,800,000** clients | 5,713 MB | 8,136 MB | 13,907 MB | 2,085 MB | 1,800 MB | 2,649 MB | 19.5 % | | **2,000,000** clients | 5,972 MB | 9,014 MB | 13,747 MB | 2,245 MB | 1,990 MB | 2,842 MB | 22.1 % | | **2,022,026** clients | 5,890 MB | 9,112 MB | 13,687 MB | 2,305 MB | 2,010 MB | 2,874 MB | 21.7 % | **New clients** Clients / second 12,412 745,486 clients in 60 s, 100 at a time Let in after, p50 7.04ms connected 2.10 ms · TCP 0.24 ms Let in after, p99 10.4ms max 21.3 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **7.0 vCPU** · Redis **0.5 vCPU** · whole server busy **91 %** · load generator busy **26 %** am_ws_load · connect with both tokens and subscribe · 1 server **One person, 1,000 a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 10 connections Notifications / second 983 60,010 received by 10,000 clients Delivery p50 1.01ms average 1.04 ms Delivery p99 1.72ms max 5.91 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.3 vCPU** · Redis **0.0 vCPU** · whole server busy **4 %** · load generator busy **3 %** autocannon · A notification for one person, 1,000 a second am_ws_load · what the clients received **One person, as many as the servers take** Calls / second 24,592 1,475,433 calls in 60 s, 100 connections Notifications / second 24,305 1,475,533 received by 10,000 clients Delivery p50 3.88ms average 3.93 ms Delivery p99 5.66ms max 529 ms Not delivered 0 0 calls failed (Server during this run) API Maker **7.7 vCPU** · Redis **0.3 vCPU** · whole server busy **97 %** · load generator busy **28 %** autocannon · A notification for one person, as many as the server takes am_ws_load · what the clients received **Broadcast, as many as the servers take** Calls / second 222 13,321 calls in 60 s, 10 connections Notifications / second 217,711 13,330,000 received by 1,000 clients Delivery p50 36.7ms average 36.7 ms Delivery p99 56.8ms max 77.6 ms Not delivered 0 0 calls failed (Server during this run) API Maker **6.9 vCPU** · Redis **0.3 vCPU** · whole server busy **89 %** · load generator busy **32 %** autocannon · A broadcast to 1,000 clients, as many as the server takes am_ws_load · what the clients received **One server stops.** With 1,516,519 clients connected, API Maker was restarted on the only server : every client was closed with `1001`, waited one to five seconds, and came back to it. Clients dropped 1,516,519 100 % of 1,516,519 All back after 221.1s on the server, restarted A client was away, p50 111.3s its own wait of 1 to 5 s counted A client was away, p99 180.7s the longest : 189 s They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,000 arrived**, in 1.06 ms (p50) and 51.7 ms (p99). A client whose subscription had not come back with it would have been told nothing. ### 2 × 4 vCPU · 8 GB | | | |---|---| | API servers | 2 × Dedicated 8 GB (g6-dedicated-4) : 4 dedicated vCPUs and 8 GB each, $144 a month in all. API Maker and its two sandboxes on each, attached to the data server by the installer (`--secondary`) | | Data server | Dedicated 8 GB (g6-dedicated-4) : AMD EPYC 7642 48-Core Processor, 4 dedicated vCPUs (KVM). MongoDB 8.0.10 and Redis 7.0.5 of API Maker, in Docker ; its own API Maker stopped | | CPU | AMD EPYC 7642 48-Core Processor | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Network limits | as the installer sets them, on every API server : 2,032,896 connections tracked (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted, 2,032,896 open files. The memory of all its TCP connections together : raised by API Maker as the clients came, to 1.9 GB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) | | Load generator | Dedicated 32 GB (g6-dedicated-16) : AMD EPYC 7642 48-Core Processor, 16 dedicated vCPUs. The clients go to the API servers in turn, as a load balancer hands them out ; autocannon calls every API server at the same time | | Network | A VLAN of the same data centre, round trip 0.32 ms (ping) | | Date | 14 October 2026, 03:20 to 04:00 UTC | Clients connected 1,915,960 957,980 on each of 2 servers Memory per client 8.8KB API Maker 3.2 · kernel 4.5 · Redis 1.1 New clients / second 12,696 both tokens and a subscription · 21,417 without one Notification delivered in 1.18ms p50 at 1,000 a second · p99 1.80 ms The run stopped adding clients at **1,915,960** : the memory of the server `api-1` was full. 1,072 MB of its 7,941 MB were still counted as available, and Linux had moved 683 MB to the swap since the clients began to connect, to make that room : 389 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server). > Diagram : Clients connected and memory used during the run > > The run of this server, second after second : the WebSocket clients connected, up to 1,915,960, and the memory the server used, up to 13,978 MB of 15,882 MB. | Clients connected | API Maker, all servers | Linux kernel, all servers | API servers, used | Least available on a server | Redis (its data) | Data server, used | CPU busy | |---|--:|--:|--:|--:|--:|--:|--:| | No client (at rest) | 225 MB | 338 MB | 1,341 MB | 7,262 MB | 2 MB | 703 MB | 0.3 % | | **10,000** clients | 285 MB | 479 MB | 2,313 MB | 6,775 MB | 12 MB | 714 MB | 1.7 % | | **100,000** clients | 564 MB | 789 MB | 2,860 MB | 6,495 MB | 103 MB | 913 MB | 1.0 % | | **200,000** clients | 875 MB | 1,236 MB | 3,532 MB | 6,156 MB | 204 MB | 1,040 MB | 2.1 % | | **400,000** clients | 1,529 MB | 2,131 MB | 4,936 MB | 5,452 MB | 404 MB | 1,217 MB | 3.7 % | | **600,000** clients | 2,178 MB | 3,028 MB | 6,332 MB | 4,730 MB | 625 MB | 1,452 MB | 5.7 % | | **800,000** clients | 2,787 MB | 3,921 MB | 7,709 MB | 4,026 MB | 810 MB | 1,637 MB | 7.6 % | | **1,000,000** clients | 3,459 MB | 4,813 MB | 9,150 MB | 3,289 MB | 996 MB | 1,828 MB | 9.8 % | | **1,200,000** clients | 4,065 MB | 5,696 MB | 10,517 MB | 2,585 MB | 1,249 MB | 2,093 MB | 12.1 % | | **1,400,000** clients | 4,672 MB | 6,545 MB | 11,926 MB | 1,877 MB | 1,430 MB | 2,270 MB | 13.8 % | | **1,600,000** clients | 5,271 MB | 7,398 MB | 12,820 MB | 1,518 MB | 1,619 MB | 2,475 MB | 16.3 % | | **1,800,000** clients | 5,774 MB | 8,263 MB | 13,795 MB | 1,027 MB | 1,800 MB | 2,729 MB | 19.1 % | | **1,915,960** clients | 5,569 MB | 8,758 MB | 13,708 MB | 1,051 MB | 1,910 MB | 2,781 MB | 20.1 % | **New clients** Clients / second 12,696 762,499 clients in 60 s, 100 at a time Let in after, p50 6.32ms connected 1.66 ms · TCP 0.24 ms Let in after, p99 14.0ms max 45.5 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **7.3 vCPU** · Redis **0.8 vCPU** · whole server busy **94 %** · load generator busy **28 %** am_ws_load · connect with both tokens and subscribe · 2 servers **One person, 1,000 a second** Calls / second (paced) 1,000 60,004 calls in 60 s, 10 connections Notifications / second 984 60,014 received by 10,000 clients Delivery p50 1.18ms average 1.19 ms Delivery p99 1.80ms max 10.0 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.4 vCPU** · Redis **0.1 vCPU** · whole server busy **5 %** · load generator busy **3 %** autocannon · A notification for one person, 1,000 a second · server 1 of 2 autocannon · A notification for one person, 1,000 a second · server 2 of 2 am_ws_load · what the clients received **One person, as many as the servers take** Calls / second 25,389 1,523,298 calls in 60 s, 100 connections Notifications / second 24,977 1,523,398 received by 10,000 clients Delivery p50 3.75ms average 3.95 ms Delivery p99 6.31ms max 530 ms Not delivered 0 0 calls failed (Server during this run) API Maker **7.8 vCPU** · Redis **0.6 vCPU** · whole server busy **99 %** · load generator busy **46 %** autocannon · A notification for one person, as many as the server takes · server 1 of 2 autocannon · A notification for one person, as many as the server takes · server 2 of 2 am_ws_load · what the clients received **Broadcast, as many as the servers take** Calls / second 255 15,275 calls in 60 s, 10 connections Notifications / second 228,910 15,285,000 received by 1,000 clients Delivery p50 39.3ms average 1,295 ms Delivery p99 6,701ms max 6,902 ms Not delivered 0 0 calls failed (Server during this run) API Maker **7.2 vCPU** · Redis **0.6 vCPU** · whole server busy **91 %** · load generator busy **32 %** (Told for 66.8 s) The calls came faster than the server tells its clients : it went on telling them for **5.5 s** after the calls stopped, and API Maker held up to **594 MB** while they waited. Notifications per second counts the whole of that time ; the delivery times are the times of notifications which waited their turn. autocannon · A broadcast to 1,000 clients, as many as the server takes · server 1 of 2 autocannon · A broadcast to 1,000 clients, as many as the server takes · server 2 of 2 am_ws_load · what the clients received **One server stops.** Nobody runs a cluster full : the servers which are left need room for the clients of the one which stops. So the newest clients left first, down to **766,384** : what 1 of the 2 servers hold when each of them is 80 % full. API Maker was then stopped on one of the servers (`systemctl stop api_maker_be`) and stayed down : its clients were closed with `1001`, waited one to five seconds, and connected to the servers which were left. Clients dropped 383,192 50 % of 766,384 All back after 68.0s on the 1 server left A client was away, p50 36.4s its own wait of 1 to 5 s counted A client was away, p99 55.8s the longest : 57.9 s They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,002 arrived**, in 1.85 ms (p50) and 144 ms (p99). A client whose subscription had not come back with it would have been told nothing. ### 4 × 2 vCPU · 4 GB | | | |---|---| | API servers | 4 × Dedicated 4 GB (g6-dedicated-2) : 2 dedicated vCPUs and 4 GB each, $144 a month in all. API Maker and its two sandboxes on each, attached to the data server by the installer (`--secondary`) | | Data server | Dedicated 8 GB (g6-dedicated-4) : AMD EPYC 7642 48-Core Processor, 4 dedicated vCPUs (KVM). MongoDB 8.0.10 and Redis 7.0.5 of API Maker, in Docker ; its own API Maker stopped | | CPU | AMD EPYC 7642 48-Core Processor · AMD EPYC 7713 64-Core Processor | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Network limits | as the installer sets them, on every API server : 1,002,240 connections tracked (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted, 1,048,576 open files. The memory of all its TCP connections together : raised by API Maker as the clients came, to 979 MB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) | | Load generator | Dedicated 32 GB (g6-dedicated-16) : AMD EPYC 7713 64-Core Processor, 16 dedicated vCPUs. The clients go to the API servers in turn, as a load balancer hands them out ; autocannon calls every API server at the same time | | Network | A VLAN of the same data centre, round trip 0.51 ms (ping) | | Date | 14 October 2026, 03:26 to 04:05 UTC | Clients connected 1,619,372 404,843 on each of 4 servers Memory per client 8.6KB API Maker 3.2 · kernel 4.4 · Redis 1.1 New clients / second 10,297 both tokens and a subscription · 17,882 without one Notification delivered in 1.37ms p50 at 1,000 a second · p99 2.51 ms The run stopped adding clients at **1,619,372** : the memory of the server `api-2` was full. 456 MB of its 3,916 MB were still counted as available, and Linux had moved 266 MB to the swap since the clients began to connect, to make that room : 190 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server). > Diagram : Clients connected and memory used during the run > > The run of this server, second after second : the WebSocket clients connected, up to 1,619,372, and the memory the server used, up to 13,792 MB of 15,660 MB. | Clients connected | API Maker, all servers | Linux kernel, all servers | API servers, used | Least available on a server | Redis (its data) | Data server, used | CPU busy | |---|--:|--:|--:|--:|--:|--:|--:| | No client (at rest) | 417 MB | 630 MB | 2,478 MB | 3,288 MB | 2 MB | 721 MB | 0.7 % | | **10,000** clients | 491 MB | 749 MB | 3,088 MB | 3,115 MB | 12 MB | 718 MB | 1.6 % | | **100,000** clients | 790 MB | 1,079 MB | 3,710 MB | 2,954 MB | 103 MB | 906 MB | 1.2 % | | **200,000** clients | 1,091 MB | 1,527 MB | 4,440 MB | 2,775 MB | 204 MB | 1,023 MB | 2.1 % | | **400,000** clients | 1,734 MB | 2,421 MB | 5,911 MB | 2,392 MB | 404 MB | 1,204 MB | 4.4 % | | **600,000** clients | 2,388 MB | 3,305 MB | 7,358 MB | 2,016 MB | 625 MB | 1,459 MB | 6.1 % | | **800,000** clients | 2,995 MB | 4,155 MB | 8,723 MB | 1,665 MB | 810 MB | 1,628 MB | 7.8 % | | **1,000,000** clients | 3,673 MB | 5,006 MB | 10,180 MB | 1,301 MB | 996 MB | 1,815 MB | 9.6 % | | **1,200,000** clients | 4,280 MB | 5,864 MB | 11,512 MB | 941 MB | 1,249 MB | 2,077 MB | 11.8 % | | **1,400,000** clients | 4,790 MB | 6,713 MB | 12,967 MB | 567 MB | 1,430 MB | 2,265 MB | 14.9 % | | **1,600,000** clients | 5,079 MB | 7,560 MB | 13,681 MB | 455 MB | 1,619 MB | 2,450 MB | 16.3 % | | **1,619,372** clients | 5,077 MB | 7,645 MB | 13,764 MB | 454 MB | 1,638 MB | 2,490 MB | 16.2 % | **New clients** Clients / second 10,297 618,456 clients in 60 s, 100 at a time Let in after, p50 3.91ms connected 1.12 ms · TCP 0.34 ms Let in after, p99 30.2ms max 53.5 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **6.6 vCPU** · Redis **1.0 vCPU** · whole server busy **88 %** · load generator busy **29 %** am_ws_load · connect with both tokens and subscribe · 4 servers **One person, 1,000 a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 8 connections Notifications / second 983 60,003 received by 10,000 clients Delivery p50 1.37ms average 1.44 ms Delivery p99 2.51ms max 12.2 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.4 vCPU** · Redis **0.1 vCPU** · whole server busy **5 %** · load generator busy **4 %** autocannon · A notification for one person, 1,000 a second · server 1 of 4 autocannon · A notification for one person, 1,000 a second · server 2 of 4 autocannon · A notification for one person, 1,000 a second · server 3 of 4 autocannon · A notification for one person, 1,000 a second · server 4 of 4 am_ws_load · what the clients received **One person, as many as the servers take** Calls / second 25,997 1,559,712 calls in 60 s, 100 connections Notifications / second 25,566 1,559,812 received by 10,000 clients Delivery p50 3.70ms average 3.77 ms Delivery p99 6.54ms max 26.1 ms Not delivered 0 0 calls failed (Server during this run) API Maker **7.8 vCPU** · Redis **0.9 vCPU** · whole server busy **99 %** · load generator busy **64 %** autocannon · A notification for one person, as many as the server takes · server 1 of 4 autocannon · A notification for one person, as many as the server takes · server 2 of 4 autocannon · A notification for one person, as many as the server takes · server 3 of 4 autocannon · A notification for one person, as many as the server takes · server 4 of 4 am_ws_load · what the clients received **Broadcast, as many as the servers take** Calls / second 276 16,562 calls in 60 s, 8 connections Notifications / second 272,609 16,570,000 received by 1,000 clients Delivery p50 25.6ms average 27.9 ms Delivery p99 63.0ms max 113 ms Not delivered 0 0 calls failed (Server during this run) API Maker **7.8 vCPU** · Redis **0.8 vCPU** · whole server busy **98 %** · load generator busy **38 %** autocannon · A broadcast to 1,000 clients, as many as the server takes · server 1 of 4 autocannon · A broadcast to 1,000 clients, as many as the server takes · server 2 of 4 autocannon · A broadcast to 1,000 clients, as many as the server takes · server 3 of 4 autocannon · A broadcast to 1,000 clients, as many as the server takes · server 4 of 4 am_ws_load · what the clients received **One server stops.** Nobody runs a cluster full : the servers which are left need room for the clients of the one which stops. So the newest clients left first, down to **971,623** : what 3 of the 4 servers hold when each of them is 80 % full. API Maker was then stopped on one of the servers (`systemctl stop api_maker_be`) and stayed down : its clients were closed with `1001`, waited one to five seconds, and connected to the servers which were left. Clients dropped 242,906 25 % of 971,623 All back after 38.0s on the 3 servers left A client was away, p50 14.5s its own wait of 1 to 5 s counted A client was away, p99 28.2s the longest : 31.0 s They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,000 arrived**, in 1.33 ms (p50) and 2.45 ms (p99). A client whose subscription had not come back with it would have been told nothing. ## Questions ### How do I scale API Maker WebSockets to N users ? Add API Maker servers behind a load balancer. Each server holds the clients which reached it (8.5 to 8.8 KB of memory per client), and all of them share one Redis, which carries every notification to the server which holds the client. Count N × 8.5 to 8.8 KB of memory over the servers, and one spare server. ### Should I run one big server or several small ones ? For the same price they hold about the same number of clients (2,022,026 on 1 × 8 vCPU · 16 GB, 1,915,960 on 2 × 4 vCPU · 8 GB, 1,619,372 on 4 × 2 vCPU · 4 GB) and let in about as many new clients a second. Several servers lose only their share of the clients when one stops (50 % on 2 × 4 vCPU · 8 GB, 25 % on 4 × 2 vCPU · 4 GB) and can be restarted one at a time ; one big server is less to run. Above a few hundred thousand users, several servers. ### Do WebSockets need sticky sessions ? No. A WebSocket is one long connection : it stays on the server it reached. What is said to it can come from any server, through Redis. ### What limits the number of WebSocket connections ? Memory : 8.5 to 8.8 KB per client, the kernel and Redis included. The installer sizes the other limits of a server from its memory, so that memory is what ends : the open files of the service and the table of the connections the firewall of Linux tracks, 256 for each MB (with 1,048,576 open files, a server of 16 GB would stop at about a million clients with half of its memory left). Behind a proxy : the ports it reaches one server from (about 64,000 per address) and its own memory for each connection. ### What happens to the clients when a server stops ? API Maker closes them with the code 1001 (Server is going away). They connect again, to another server when there is one, and subscribe again. Measured on 4 × 2 vCPU · 4 GB : 242,906 clients were all back on the other servers after 38.0 s. --- # How the API Maker WebSocket benchmarks are made > How the WebSocket benchmarks of API Maker are made - Linode servers of 1 to 8 vCPUs, real clients with both tokens and a subscription, autocannon for the calls, 60 s a run, the events and the commands. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html The WebSocket benchmarks answer four questions : how many clients one server holds, how much memory a client takes, how to serve N users, and whether one big server beats several small ones. This page shows how every number was measured, so you can check it, or measure it again. | | | |---|---| | Servers | The seven [Linode](https://www.linode.com) servers of the [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html), in Mumbai, from 1 to 8 vCPUs, with MongoDB and Redis on the same machine. Plus three clusters of the same price : 8 dedicated vCPUs and 16 GB as one, two or four API servers, with MongoDB and Redis on a server of their own. | | Clients | Real WebSocket clients, from a second server in the same data centre. Each one connects with two tokens, subscribes to its own notifications, and answers the pings of the server. | | HTTP calls | autocannon 8, as in the API benchmarks : the emit event WS API, the insert API of a table, get all. | | Runs | 60 seconds each, after 5 seconds of warm-up. All the servers were measured side by side on 14 October 2026, each with its own load generator. | | Installation | The API Maker installer with its default answers and no reverse proxy : clients reach API Maker on its own port `38246`. One setting changed : the sandboxes keep running. | | Data | The [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) : 10 customers with 10 columns each, in MongoDB. | | Samples | Once a second, on every server and on the load generator : memory, CPU (with steal time), the API Maker process and its open files, every container, the sockets of the kernel and the connections its firewall tracks. | ## What a client is Every client does what a real application does : ```javascript const ws = new WebSocket('ws://:38246/' + '?x-am-authorization=' + apiUserToken // the token of an API user + '&x-am-user-authorization=' + personToken); // the token of a person : a row of `customers` ws.onmessage = (e) => { const msg = JSON.parse(e.data); if (msg.type === 'CONNECTED') { ws.send(JSON.stringify({ objType: 'REGISTER', onEvents: [{ eventType: 'CUSTOM_WS_EVENTS', apiName: 'order-updates', condition: { conditionType: 'RESPONSE', criteria: { recipientId: myId } }, // its own id getEventData: true, }], })); } else if (msg.type === 'NOTIFICATION') { received(msg.response.eventData); } }; ``` - **Both tokens** : `x-am-authorization` is the token of an [API user](https://docs.apimaker.dev/v4/docs/apis-security/api-user-permission.html), `x-am-user-authorization` the token of a row of the `customers` table, made by a [DB token generator](https://docs.apimaker.dev/v4/docs/authorization/AMDB.html). API Maker checks both when the client connects, and closes the client when one of them runs out. - **Its own subscription** : every client waits for the notifications of one person, itself. This is the pattern of the [WebSocket events](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html) page, and the most expensive one for Redis : a key, a place in a list and a channel for every client. - **It answers the pings** : API Maker pings every client once a minute, and takes a client which sent nothing for two and a half minutes for gone. A browser or a Node.js process holds a few thousand such clients. To open millions from one machine, the benchmarks use `am_ws_load`, a small Rust program written for them : a client is a socket, a buffer of 512 bytes and a task, about 3 KB of the load generator. It speaks WebSocket the way a browser does (handshake, masked frames, pongs, close), counts every message, and measures how late each notification arrives. ## The servers | | Server under test | Load generator | |---|---|---| | Runs | API Maker, its MongoDB and Redis, its two sandboxes | The WebSocket clients (`am_ws_load`) and autocannon | | Plan | Shared or dedicated CPU, as named on each page | A dedicated Linode, big enough to hold as many sockets as the server it measures : 4 vCPUs for the servers of 1 and 2 vCPUs, 8 for 4 vCPUs, 16 for 16 GB and the clusters, 32 (64 GB) for 32 GB | | System | Ubuntu 24.04 LTS | Ubuntu 24.04 LTS, Node.js 24.21.0, autocannon 8.0.0 | | Network | A VLAN of the data centre | The same VLAN, 0.4 ms away (ping) | The load generator samples itself every second too : every page says how busy it was at most. ### More than 64,000 clients from one machine A TCP connection is named by four numbers : the address and port it comes from, and the address and port it goes to. So one address can open only about 64,000 connections to one port of a server. The load generator takes more addresses on the VLAN, and keeps each one under about 25,000 connections to a server : 10 addresses for the server of 1 GB, 20 for 4 GB, 40 for 8 GB, 100 for 16 GB and 150 for 32 GB. (Past about 32,000 connections from one address, Linux 6 spends a lot of CPU finding the port of each new one.) It also gets room in its own tables : ```sh sysctl -w net.ipv4.ip_local_port_range="1024 65535" net.ipv4.tcp_tw_reuse=1 fs.nr_open=8388608 net.netfilter.nf_conntrack_max=8388608 sysctl -w net.ipv4.tcp_mem=" " ``` The last line is for the moments when every client does something at once : unless told otherwise, Linux gives all the TCP connections of a machine together 9 % of its memory. (On the server under test, API Maker raises that memory itself, as its clients come.) A reverse proxy in front of API Maker meets the same limit : it reaches one server from one address about 64,000 times, 28,000 as Linux sets it up. [Scale to N users](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#limits) says what to do about it. ## The installation API Maker is installed on a fresh server with its [installer](https://docs.apimaker.dev/v4/docs/getting-started/install-on-server.html), its default answers and no reverse proxy : ```sh bash install.sh --default --primary --caddy=no --ssl=no --qa_uat_prod=no --package=api-maker-4.0.0-linux-x64.tar.gz ``` The installer sets up Docker, MongoDB 8.0.10 and Redis 7.0.5 in Docker, swap, and API Maker as a systemd service. It also makes room for many connections : - **Open files** : every client is an open file of the service. The service may open as many as the firewall tracks connections (256 for each MB of memory, 1,048,576 at least : `LimitNOFILE` is 8,216,320 on the server of 32 GB), and Linux lets a process have that many (`fs.nr_open`). - **The network** : for a server of 8 GB, for example : **/etc/sysctl.d/90-api-maker.conf, on a server of 8 GB** ```ini net.netfilter.nf_conntrack_max = 2032896 net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30 net.core.somaxconn = 16384 net.ipv4.tcp_max_syn_backlog = 16384 fs.nr_open = 4065792 ``` with `LimitNOFILE=2032896` in the service of API Maker. While it runs, API Maker raises the memory Linux gives all its TCP connections together (`net.ipv4.tcp_mem`) as its clients come : two pages for each open connection, never above a quarter of the memory of the server. The page of each server says what it was at the end of the run. One setting is changed, in `~/config/.env`, as in the API benchmarks : `am__sandbox__removeSandboxInactiveSinceMinutes=1440` keeps the two sandboxes of the account running for the whole run, so their memory is counted. ### The table of tracked connections Docker makes Linux track every connection of the server in a table (`nf_conntrack`), the ones of API Maker too. As Linux sets it up, that table holds 262,144 connections on a server of 4 GB or more (65,536 on 1 GB), and a connection which closed stays in it for two more minutes. Once the table is full, the kernel drops new connections without a word, except in its own log (`nf_conntrack: table full, dropping packet`). So the installer gives the table room for 256 connections per MB of memory, twice the clients the memory holds (131,072 at least, 16,777,216 at most : an entry is about 320 bytes, taken only while its connection is there), and lets a closed connection go after 30 seconds. API Maker says at its start how many connections the table holds, and warns when that is fewer than its memory has room for. On a server installed before, run the installer again, or : ```sh sysctl -w net.netfilter.nf_conntrack_max=1048576 net.netfilter.nf_conntrack_tcp_timeout_time_wait=30 ``` ## The account The account of the [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html#the-data) (its tables in MongoDB, its API user, its DB token generator), with five events on its **WebSocket Events** page, each taking the token of the DB token generator : | Event | What it is | |---|---| | `order-updates` | A notification for one person : every client subscribes to it with its own id in the criteria. | | `announcements` | A broadcast : clients subscribe to it without a condition, and one emit reaches all of them. | | `checked-token` | `order-updates` with a can user connect code which reads the person of the token. | | `checked-database` | The same, with a code which also reads the person from the database. | | `checked-sandbox` | The same, with a code which reads the clock, so that it runs in a sandbox. | | Insert of `inserts_public` | The event of an API of a table (`SCHEMA_POST_BULK_INSERT`) : every saved row is told to the clients which subscribed. | A system API answers nobody until its settings say who may call it. The emit event WS API takes both tokens : **System API settings of EMIT_EVENT_WS** ```typescript import * as T from 'types'; let systemApi: T.ISystemApiSettingsTypes = { enableCaching: false, acceptOnlyEncryptedData: false, apiAccessType: T.EAPIAccessType.TOKEN_ACCESS, authProviders: ['bench_token_mongodb'], }; module.exports = systemApi; ``` The three can user connect codes are on the page of each server, with where each of them ran. Before the runs, a real WebSocket client (the one of Node.js) checks every event : a client with both tokens subscribes to each one, a notification for one person reaches that person and nobody else, a broadcast reaches everybody, an insert reaches the clients of its table with its row, a client without the token of the person is refused by every event, and a client with a wrong token is told why and closed with `1000`. ## The runs Every measured run lasts 60 seconds, and the server rests 10 seconds between two runs. When the server is only watched with its clients connected (at rest, at each level of clients), it is watched for 30 seconds. ### At rest API Maker is restarted, its two sandboxes are started, the swap is emptied back into memory, and the server waits 30 seconds with no client : this is the memory *at rest* of the pages. Then autocannon loads get all with both tokens (100 connections), with no WebSocket client connected. ### New clients per second 100 clients at a time connect, are let in and leave, one after the other, for 60 seconds after 5 seconds of warm-up : what `autocannon -c 100 -d 60` does for requests, for clients. A client which leaves sends a close and waits for the close of the server. Six runs : | Run | What each client does | |---|---| | Connect : the token of the API user | Connects with `x-am-authorization`, is told `CONNECTED`, leaves. | | Connect : both tokens | The same, with `x-am-user-authorization` too. | | Connect and subscribe | Both tokens, `CONNECTED`, `REGISTER` for `order-updates` with its own criteria, the answer, leaves. | | … with a can user connect code | The same on `checked-token`, `checked-database` and `checked-sandbox`. | The times count from the start of the TCP connection : to the connection itself, to `CONNECTED`, to the answer of `REGISTER`, and to the end of the close. ### Notifications 10,000 clients connect and stay (5,000 on the server of 1 GB), each with its subscription. autocannon then makes the HTTP calls which notify them, and the clients count what they receive : | Kind | The call | Who is told | |---|---|---| | For one person | `POST /api/system-api//emit-event-ws`, both tokens, `{ name, eventData: { recipientId, … } }` | The one client whose criteria is that `recipientId` : every call names another one. | | A broadcast | The same API, on `announcements` | 1,000 more clients, which subscribed without a condition. | | Rows of a table | `POST /api/schema//mongodb/am_bench/inserts_public/save-single-or-multiple`, a row of the dataset | 100 clients which subscribed to the insert API of the table, each told the row. | Each kind is measured twice : - **At a pace** far under what the server takes : 1,000 notifications a second for one person, 5 broadcasts a second, 50 inserts a second. It shows how long a notification takes. - **With no pace** : as many calls as the server answers (100 connections ; 10 for the broadcast). It shows how many notifications a second the server tells. When calls come faster than the server tells its clients, the notifications wait their turn inside API Maker and keep arriving after the calls stopped : the run waits for all of them, and *notifications per second* counts that whole time. **How a delivery is timed.** autocannon writes the time into the body of every request, just before it sends it (`t` of the emitted data, `phone` of an inserted row : milliseconds since 1970). The client reads it back in the notification and compares it with its own clock. autocannon and the clients run on the same machine, so both times come from one clock. A delivery is the whole way : the HTTP call, API Maker, Redis, the WebSocket. **Calls and notifications.** autocannon counts the answers it read before its 60 seconds end. The calls it had sent by then (one per connection at most) are answered too, and what they emit is told, so the clients receive a few more notifications than calls are counted : ten more with 10 connections, a thousand more when one broadcast to 1,000 clients was on its way. *Not delivered* counts the notifications of the counted calls which no client received. ### As many clients as fit More clients connect, level after level (for a server of 8 GB : 50,000, 100,000, then every 100,000), at a pace the server follows : 1,000 a second per vCPU, about four fifths of what it lets in when every client subscribes. At each level they wait 30 seconds while the server is sampled, and Redis is asked what it holds ; the last level is held 60 seconds. Clients stop being added when one of these happens : - **The memory is full** : what the server has available (`MemAvailable`), minus what Linux moved to the swap since the clients began, is under 5 % of its memory (64 MB at least). Linux moves memory nobody touches (of MongoDB, of the sandboxes) to the swap long before a server is short of it, which makes as much memory available again : that is counted as memory the clients took. So the clients of the pages fit in memory, not in the swap. - **Nobody else is let in** : no client is let in for 20 seconds, or more than 1 % of a level is refused. API Maker answers `503` past the connections it takes (its open files, minus a share kept for the calls of the APIs). - **The most the run opens** for that server, which stays under the table of the firewall : a full table drops every new connection, SSH included. *Per client* is the slope of a line through the levels : what one more client costs of API Maker (the resident memory of its process, plus what Linux moved of it to the swap on a small server), of the kernel (its slab, which holds the sockets and the tracked connections), of Redis (the memory of its container, and of its data) and of the whole server (what it has less of available). ### One more subscription, and a broadcast to everybody At the second level (the first one on the server of 1 GB), with memory still left, every connected client sends a second `REGISTER`, for `announcements`. The server waits 30 seconds with two subscriptions per client : the difference with the level before is what a subscription costs. Then three calls of the emit event WS API tell everybody, one after the other, and the clients time the first notification, the median and the last. Every client then takes its second subscription back (`UNREGISTER`), and the levels go on. ### With every client connected Once the server is full : the notification for one person again, at a pace and with no pace, and get all with both tokens (autocannon, 100 connections), while every client waits. ### A restart API Maker is restarted (`systemctl restart api_maker_be`) with three quarters of the clients it holds : the newest ones leave first. Nobody runs a server full, and a restarted server needs room : every client comes back within the same seconds, and waits for its turn with its request in the kernel, about 4 KB each. API Maker closes its clients with the code `1001` (*Server is going away*). Each client waits one second, plus up to four more of its own choosing, then connects again and sends its `REGISTER` again, as the [WebSocket events](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html#staying-connected) page tells an application to do. The server which comes back lets 256 clients in at a time, and handles the messages of 256 at a time : the others wait for their turn. The run counts the clients until they are all back, and how long each one was away. Then every client is told again, each for itself, 1,000 notifications a second for 60 seconds : a client whose subscription had not come back would be told nothing. Redis is asked too, whether it holds the same channels and keys as before the restart. ### Every client leaves at once At the very end, every client closes its connection in the same second, as when a network or a load balancer in front of the server goes down. The run counts the seconds until the server has no socket of a client left open, and until Redis holds nothing of them any more : Redis is asked every two seconds, and once more five seconds after it was found empty of them. ### Several servers A cluster is one data server (the MongoDB and Redis of API Maker, installed with `--primary` ; its own API Maker is stopped) and API servers installed with `--secondary`, which hold the clients. The clients go to the API servers in turn, as a load balancer which counts connections hands them out, and autocannon calls every API server at the same time, its 100 connections shared out. The runs are the ones above, and clients are added until the memory of one of the servers is full. Instead of a restart, **one API server stops and stays down** : its clients go to the servers which are left, as a load balancer spreads them. The servers which are left need room for those clients, so before the server stops, the newest clients leave, down to what the other servers hold when each of them is 80 % full (40 % of the clients a cluster of two held, 60 % with four). No load balancer stands between the clients and the servers : the pages measure API Maker. A proxy adds its own memory per connection, and the ports it reaches a server from. The data server takes MongoDB and Redis off the API servers, so an API server of a cluster has all its memory for clients : the 8 vCPU · 16 GB server holds 2,022,026 clients as a cluster of one, and 1,732,035 on [its own page](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html), where MongoDB and Redis share its memory. ## Memory and CPU A small script on every server reads `/proc` and the cgroups of the containers once a second : | Measure | What it is | |---|---| | API Maker | The resident memory (RSS) of the `api_maker_be` process, its CPU in percent of one core, its open files. | | Containers | Redis, MongoDB and the sandboxes : memory as `docker stats` counts it, and CPU. | | Linux kernel | Its slab : the sockets, the tracked connections, and everything else the kernel keeps. The TCP sockets in use and the connections the firewall tracks are counted too. | | Whole server | Memory used (total − available), swap used, pages swapped in and out. | | Pressure | The share of the last ten seconds in which tasks of the server waited for memory, and for the CPU (`/proc/pressure`) : a server short of memory waits for it, one which only moved what nobody touches to its swap does not. | | CPU | User, system, softirq, idle and steal : the time the hypervisor gave to other servers. | Redis is asked too, after each level and never during a run : the memory of its data (`used_memory`), its keys, and the channels the servers listen on. ## What these numbers are not - **No HTTPS, no reverse proxy.** Caddy (which the installer puts in front by default) and TLS take memory for every connection and CPU for every handshake, on the machine they run on. - **Clients which wait.** A client with one subscription, told a notification now and then, is what most applications have. A client told a hundred messages a second costs CPU and a larger buffer. - **One data centre.** The clients are 0.4 ms away. Clients on the internet have slower connections : more of what they are told waits in the buffers of the server. - **One person behind every token.** All clients connect with the tokens of the same API user and the same person. API Maker keeps what the tokens said for each client, so different people would cost the same. - **Not a published version.** The pages say API Maker 4.0.0 : the number of the build that was measured (commit `423a34c` and the WebSocket core of 14 October 2026), before the beta releases were numbered. ## Run it yourself 1. Make two servers in the same data centre, and install API Maker on the first one. 2. Add an event to **WebSocket Events**, give your group *all WebSocket events*, and give the emit event WS system API its settings, as above. 3. On the second server, open your clients with any WebSocket library and the code of [What a client is](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html#what-a-client-is), ask for the two tokens with the [token API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-token-api.html), and call the emit event WS API with autocannon : ```sh autocannon -c 100 -d 60 -m POST \ -H "x-am-authorization: " -H "x-am-user-authorization: " -H "content-type: application/json" \ -b '{"name":"order-updates","eventData":{"recipientId":"42","order_no":1001}}' \ "http://:38246/api/system-api//emit-event-ws" ``` The results : [WebSocket benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/index.html). --- # API Maker WebSocket benchmark : 1 vCPU, 1 GB RAM (Linode shared CPU) > API Maker WebSockets on 1 shared vCPU, 1 GB (Linode) : 26,484 clients connected at once, 9 KB each, 2,602 new clients a second, with memory and outputs. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html WebSocket benchmark · Linode (Akamai Cloud) · Shared CPU · 14 October 2026 **1 vCPU, 1 GB RAM : 26,484 WebSocket clients connected at once.** API Maker 4.0.0 on the smallest Linode server, a Nanode 1 GB (g6-nanode-1) : 1 shared vCPU and 1 GB of RAM at $5 a month, its MongoDB and Redis on the same machine. A second server opened WebSocket clients, each with both tokens and a subscription of its own, until the memory of the server was full, while autocannon made the calls which notify them : every run 60 seconds, the memory and CPU of every part sampled each second. Clients connected 26,484 the memory was full : 149 MB left Memory per client 8.6KB API Maker 3.3 · kernel 4.3 · Redis 1.0 New clients / second 2,602 both tokens and a subscription · 5,302 without one Notification delivered in 2.51ms p50 at 1,000 a second · p99 3.82 ms ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Nanode 1 GB (g6-nanode-1), shared cpu, $5 / month | | CPU | AMD EPYC 7642 48-Core Processor, 1 shared vCPU (KVM)
KVM guest, 1 thread per core · L1d 64 KiB (1 instance) · L2 512 KiB (1 instance) · L3 16 MiB (1 instance) · BogoMIPS 4600.00 | | Memory | 1 GB (961 MB usable), swap 2.5 GB (496 MB of Linode + 2 GB made by the installer) | | Disk, region | 25 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer : one worker thread per vCPU, up to 1,048,576 open files for the service (`LimitNOFILE`), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Network limits | as the installer sets them : 246,016 connections tracked by the firewall of Linux (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted (`net.core.somaxconn`). The memory of all its TCP connections together : raised by API Maker as the clients came, to 240 MB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) : on the same server. No other database runs | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 404 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default) | | Load generator | Dedicated 8 GB (g6-dedicated-4) : AMD EPYC 7713 64-Core Processor, 4 dedicated vCPUs, Ubuntu 24.04.4 LTS. The WebSocket clients : am_ws_load, a program in Rust made for these benchmarks, a socket and a task per client, from 11 addresses of the load generator. The HTTP calls : Node.js 24.21.0, autocannon 8.0.0 | | Network | A VLAN of the same data centre, round trip 0.47 ms (ping) | | Date | 14 October 2026, 03:18 to 03:49 UTC | Only what the run needs was running : API Maker and its two sandboxes, its MongoDB and its Redis. API Maker was restarted and the swap emptied before the run. How every number was taken : [How the WebSocket benchmarks are made](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html). The APIs of this server : [1 vCPU · 1 GB, API benchmark](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-1-vcpu-1gb.html). ## The data - **The clients** connect to `ws://:38246/?x-am-authorization=&x-am-user-authorization=` : the token of an API user, and the token of a person, a row of the `customers` table of the [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`) made by a DB token generator. API Maker checks both. - **A subscription** is one `REGISTER` for the custom WebSocket event `order-updates` with a condition of its own : `{ conditionType: 'RESPONSE', criteria: { recipientId: '' } }`. It is the way [one notification reaches one person](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html). - **A notification** for one person is 141 bytes ; a row of the dataset told to the clients of a table is 321 bytes. - **The tables** are the ones of the [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html#the-data), in MongoDB : ten rows of customers, ten columns each. ## Results at a glance **New clients per second** [Connect : the token of the API user](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#connect-1-token) · 5,905 [Connect : both tokens](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#connect-2-tokens) · 5,302 [Connect with both tokens and subscribe](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#subscribe) · 2,602 [Subscribe to an event with a can user connect code](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#can-user-connect) · the code ran in the server · 2,097 [Subscribe : the code reads the database](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#can-user-connect-database) · the code ran in the sandbox · 959 [Subscribe : the code reads the clock](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#can-user-connect-sandbox) · the code ran in the sandbox · 1,960 100 clients at a time connect, are let in and leave, for 60 seconds. **Notifications per second** [A notification for one person](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#one-person) · 5,285 calls / second · 5,216 [A broadcast](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#broadcast) · 73 calls / second · 72,245 [Rows inserted in a table](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html#insert) · 416 calls / second · 40,498 As many calls as the server takes : what the clients received each second. ## How many clients fit Clients connect 1,000 a second, level after level, each with both tokens and a subscription of its own ; at each level they wait 30 seconds while the server is sampled (the level the run stops at, 60). The run stopped adding clients at **26,484** : the memory of the server was full. 139 MB of its 961 MB were still counted as available, and Linux had moved 77 MB to the swap since the clients began to connect, to make that room : 62 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server). > Diagram : Clients connected and memory used during the run > > The run of this server, second after second : the WebSocket clients connected, up to 26,484, and the memory the server used, up to 836 MB of 961 MB. API Maker · MongoDB of API Maker · Redis · Sandboxes · Linux : its sockets, Docker, the rest · Available No client at rest 5,000 clients connected 7,500 clients connected 10,000 clients connected 15,000 clients connected 20,000 clients connected 25,000 clients connected 26,484 clients connected | Clients | API Maker | Redis | Kernel | MongoDB | Sandboxes | Server, used | Available | Swap | CPU busy | |---|--:|--:|--:|--:|--:|--:|--:|--:|--:| | None (at rest) | 103 | 1 | 88 | 139 | 51 | **600** | 362 | 0 | 3.1 % | | **5,000** | 112 | 7 | 124 | 145 | 146 | **746** | 216 | 50 | 2.6 % | | **7,500** | 103 | 9 | 122 | 141 | 145 | **739** | 223 | 102 | 1.8 % | | **10,000** | 91 | 12 | 131 | 125 | 145 | **730** | 231 | 120 | 2.0 % | | **15,000** | 105 | 16 | 152 | 124 | 144 | **755** | 207 | 124 | 2.2 % | | **20,000** | 106 | 22 | 174 | 120 | 140 | **784** | 178 | 155 | 2.7 % | | **25,000** | 118 | 27 | 194 | 114 | 142 | **806** | 156 | 168 | 2.5 % | | **26,484** | 126 | 28 | 200 | 110 | 143 | **813** | 149 | 176 | 2.5 % | Memory in MB. API Maker is the resident memory of its process ; Redis is the memory of its data (`used_memory`) ; the kernel of Linux keeps every socket and every tracked connection in its slab ; a container is counted the way `docker stats` counts it. CPU busy is the whole server while the clients wait : the server pings every client once a minute, and each answers. ### Memory when the server is full With **26,484 clients** connected and waiting, of the 961 MB of the server : | Part | At rest, no client | 26,484 clients | More | |---|--:|--:|--:| | **API Maker** (process) | 103 MB | **126 MB** | + 23 MB | | Redis (container) | 3 MB | **30 MB** | + 27 MB | | Linux kernel : sockets, tracked connections (slab) | 88 MB | **200 MB** | + 112 MB | | MongoDB of API Maker (container) | 139 MB | **110 MB** | − 29 MB | | Sandboxes (2 containers) | 51 MB | **143 MB** | + 93 MB | | **Whole server**, used | 600 MB | **813 MB** | + 213 MB | | Available | 362 MB | **149 MB** | | | Swap used | 0 MB | **176 MB** | | | Open files of API Maker | 27 | **26,510** | | | Keys of Redis · channels it listens on | 13 · 5 | **52,984 · 26,489** | | MongoDB and the sandboxes grew during the runs before this one (the inserts, the code of the events), not with the clients. ### What a client costs Between 10,000 and 26,484 clients (5 levels), each client more cost the server **8.6 KB** : | Where | Per client | What it is | |---|--:|---| | **API Maker** | **3.3 KB** | The client itself : its socket and the one task which reads it, its tokens and what they said, its subscription and the channel it is told on. | | Linux kernel | 4.3 KB | The TCP socket, and the entry of the connection in the table of the firewall (Docker makes Linux track every connection). | | Redis | 1.0 KB | The subscription : its key, its place in the list of its condition, and the channel API Maker listens on. | | **In all** | **8.6 KB** | 121,927 clients per GB of memory. | Measured over every level from the first after the second subscriptions were taken back : what Linux moved of API Maker to the swap is counted with it. The memory the whole server had available went down by 5.2 KB per client : MongoDB, the sandboxes and the cache of files give some back while the clients take theirs. ## One more subscription, and a broadcast to everybody With 7,500 clients connected, every client sent a second `REGISTER`, for an event without a condition (`announcements`), 1,000 of them a second : 7,500 were taken in 7.5 s. They waited 30 seconds with two subscriptions each, were told 3 broadcasts, one call of the emit event WS API each, and took the subscription back with `UNREGISTER`. One subscription more 0.7KB per client : API Maker -0.0 KB · Redis 0.7 KB A broadcast to 7.5k clients 0.16s until the last client read it Half of them told after 92.1ms the first after 28.4 ms Clients told / second 46,688 one call, every client | Broadcast | Clients told | The call answered after | The first client | Half of them | 99 % of them | The last one | Clients told a second | |---|--:|--:|--:|--:|--:|--:|--:| | 1 | 7,500 of 7,500 | 0.18 s | 49.6 ms | 110 ms | 178 ms | **179 ms** | 41,822 | | 2 | 7,500 of 7,500 | 0.17 s | 26.3 ms | 92.5 ms | 163 ms | **164 ms** | 45,670 | | 3 | 7,500 of 7,500 | 0.16 s | 28.4 ms | 92.1 ms | 159 ms | **161 ms** | 46,688 | One call of the emit event WS API tells every client : API Maker asks Redis for the clients of the event, publishes the notification for each of them, and the server which holds a client sends it. The times are counted from the moment the call is written to the moment a client reads its notification. | Memory, 7,500 clients | One subscription each | Two subscriptions each | A subscription more, per client | |---|--:|--:|--:| | API Maker | 103 MB | 95 MB | -0.0 KB | | Redis (its data) | 9 MB | 14 MB | 0.7 KB | | Keys of Redis · channels | 15,016 · 7,505 | 22,517 · 15,005 | | | **Whole server**, less available | | | **0.7 KB** | ## New clients per second How many clients a second the server lets in : 100 clients at a time connect, are let in and leave, one after the other, for 60 seconds (after 5 seconds which are not counted). It is what a server faces when its clients all come back, after a deployment or a network cut. The times are counted from the start of the TCP connection. ### Connect : the token of the API user A client connects with `x-am-authorization` alone, is told `CONNECTED`, and leaves. API Maker checks the token of the API user and finds its groups : what every WebSocket client costs before it asks for anything. Clients / second 5,905 354,665 clients in 60 s, 100 at a time Let in after, p50 9.42ms connected 9.42 ms · TCP 0.36 ms Let in after, p99 16.8ms max 32.4 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **0.9 vCPU** · whole server busy **100 %** · load generator busy **66 %** am_ws_load · Connect : the token of the API user · 60 s ### Connect : both tokens A client connects with `x-am-authorization` and `x-am-user-authorization`, is told `CONNECTED`, and leaves. Both tokens are checked : the one of the API user, and the one of a person, made by the DB token generator of the account. Clients / second 5,302 318,458 clients in 60 s, 100 at a time Let in after, p50 10.5ms connected 10.5 ms · TCP 0.37 ms Let in after, p99 17.7ms max 39.5 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **0.9 vCPU** · whole server busy **100 %** · load generator busy **56 %** am_ws_load · Connect : both tokens · 60 s ### Connect with both tokens and subscribe The whole of what an application does : connect with both tokens, `CONNECTED`, one `REGISTER` for a custom WebSocket event with a condition of its own (`recipientId` : its user id), the answer, then leave. API Maker checks the groups and the auth provider of the event, keeps the subscription in Redis and listens on its channel ; when the client leaves, all of it is taken back. Clients / second 2,602 156,295 clients in 60 s, 100 at a time Let in after, p50 33.2ms connected 8.00 ms · TCP 0.34 ms Let in after, p99 47.5ms max 65.7 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **0.7 vCPU** · Redis **0.1 vCPU** · whole server busy **100 %** · load generator busy **33 %** am_ws_load · Connect with both tokens and subscribe · 60 s ### Subscribe to an event with a can user connect code The same, on an event whose *can user connect code* decides who may subscribe : it reads the person of `x-am-user-authorization` from `g.req.auth`. The code ran in the server itself (lean code, QuickJS). Clients / second 2,097 125,939 clients in 60 s, 100 at a time Let in after, p50 41.7ms connected 9.86 ms · TCP 0.35 ms Let in after, p99 57.8ms max 78.8 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **0.7 vCPU** · Redis **0.1 vCPU** · whole server busy **100 %** · load generator busy **27 %** am_ws_load · Subscribe to an event with a can user connect code · 60 s ### Subscribe : the code reads the database The same, with a can user connect code which also reads the person from the database (`g.sys.db.getAll` with a `find`) before it answers : one read of MongoDB for every subscription. The code ran in a sandbox of the account. Clients / second 959 57,569 clients in 60 s, 100 at a time Let in after, p50 93.8ms connected 14.0 ms · TCP 0.35 ms Let in after, p99 144ms max 194 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **0.3 vCPU** · Redis **0.1 vCPU** · MongoDB **0.2 vCPU** · sandboxes **0.3 vCPU** · whole server busy **100 %** · load generator busy **13 %** am_ws_load · Subscribe : the code reads the database · 60 s ### Subscribe : the code reads the clock The same, with a can user connect code which reads the time of the machine (`Date.now()`) : code which is not lean, so API Maker runs it in a sandbox of the account. The code ran in a sandbox of the account. Clients / second 1,960 117,720 clients in 60 s, 100 at a time Let in after, p50 45.5ms connected 8.11 ms · TCP 0.35 ms Let in after, p99 65.1ms max 88.3 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **0.6 vCPU** · Redis **0.1 vCPU** · sandboxes **0.1 vCPU** · whole server busy **100 %** · load generator busy **32 %** am_ws_load · Subscribe : the code reads the clock · 60 s ## Can user connect code An event of the WebSocket Events page can carry a *can user connect code* : API Maker runs it for every subscription to the event, with the tokens of the client in `g.req.auth` and the subscription in `g.req.eventData`, and lets the client subscribe when it returns `{ canConnect: true }`. Three codes were measured : one which reads the person of the token, one which also reads the database, one which reads the clock. **Reads the person of the token** **Can user connect code of the event checked-token : ran in the server** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { // The person of x-am-user-authorization : only somebody who signed in subscribes, from a country we serve. const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; return { canConnect: person.country === 'India', errorText: 'Not available in your country.' }; }; module.exports = main; ``` **Reads the database** **Can user connect code of the event checked-database : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // Still a customer ? One read of the database for every subscription. const rows = await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers', queryParams: { find: { customer_id: person.customer_id } } }); return { canConnect: rows.length === 1 && rows[0].country === 'India', errorText: 'Not a customer any more.' }; }; module.exports = main; ``` **Reads the clock** **Can user connect code of the event checked-sandbox : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // The time of the machine : this code runs in the sandbox of the account. const hour = new Date(Date.now()).getUTCHours(); return { canConnect: person.country === 'India' && hour >= 0, errorText: 'Not available in your country.' }; }; module.exports = main; ``` | Can user connect code | Runs in | Clients / second | Subscribed after, p50 | p99 | Against no code | |---|---|--:|--:|--:|--:| | No code | – | **2,602** | 33.2 ms | 47.5 ms | – | | Reads the person of the token | the server (QuickJS) | **2,097** | 41.7 ms | 57.8 ms | 19 % fewer | | Reads the person from the database | a sandbox of the account | **959** | 93.8 ms | 144 ms | 63 % fewer | | Reads the clock | a sandbox of the account | **1,960** | 45.5 ms | 65.1 ms | 25 % fewer | Lean code (it only reads what it is handed) runs in the server itself, with QuickJS, on the thread which serves the client. Code which needs more runs in a sandbox of the account : every subscription is then a round trip to the sandbox. ## Notifications With 5,000 clients connected, autocannon makes the HTTP calls which notify them, for 60 seconds, and the clients count what they receive and how late. Each kind of notification is measured twice : at a pace far under what the server takes, which shows how long a notification takes, and with no pace, which shows how many a second the server tells. *Delivery* is the time from the moment autocannon writes the request to the moment the client reads the notification : the HTTP call, API Maker, Redis, and the WebSocket. ### A notification for one person autocannon calls the [emit event WS API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-emit-event-ws-api.html) with both tokens ; every call names another one of the 5,000 connected clients (`recipientId`), which is the only one told. The clients measure how long each notification took from the moment its request was written. **1,000 calls a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 10 connections Notifications / second 983 60,009 received by 5,000 clients Delivery p50 2.51ms average 2.50 ms Delivery p99 3.82ms max 8.06 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · whole server busy **29 %** · load generator busy **15 %** autocannon · A notification for one person, 1,000 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 5,285 317,042 calls in 60 s, 100 connections Notifications / second 5,216 317,140 received by 5,000 clients Delivery p50 18.6ms average 18.8 ms Delivery p99 30.0ms max 65.6 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.8 vCPU** · Redis **0.1 vCPU** · whole server busy **100 %** · load generator busy **42 %** autocannon · A notification for one person, as many as the server takes am_ws_load · what the clients received ### A broadcast 1,000 more clients subscribe to an event without a condition : every call of the emit event WS API reaches all 1,000 of them. **5 calls a second** Calls / second (paced) 5 300 calls in 60 s, 1 connection Notifications / second 4,931 301,000 received by 1,000 clients Delivery p50 10.3ms average 11.1 ms Delivery p99 21.6ms max 29.4 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.1 vCPU** · whole server busy **10 %** · load generator busy **15 %** autocannon · A broadcast to 1,000 clients, 5 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 73 4,376 calls in 60 s, 10 connections Notifications / second 72,245 4,385,000 received by 1,000 clients Delivery p50 122ms average 124 ms Delivery p99 204ms max 333 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.8 vCPU** · Redis **0.1 vCPU** · whole server busy **100 %** · load generator busy **63 %** autocannon · A broadcast to 1,000 clients, as many as the server takes am_ws_load · what the clients received ### Rows inserted in a table 100 clients subscribe to the insert API of a table (`SCHEMA_POST_BULK_INSERT` on `inserts_public`, `getEventData: true`) ; autocannon inserts rows of the [dataset](https://apimaker.dev/json/benchmark_dataset.json) through the [insert API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html), and every row saved is told to each of the 100 clients, with its columns. **50 calls a second** Calls / second (paced) 50 3,000 calls in 60 s, 10 connections Notifications / second 4,930 301,000 received by 100 clients Delivery p50 51.3ms average 53.4 ms Delivery p99 103ms max 127 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.1 vCPU** · Redis **0.0 vCPU** · MongoDB **0.1 vCPU** · whole server busy **21 %** · load generator busy **13 %** autocannon · Inserts told to 100 clients, 50 inserts a second am_ws_load · what the clients received **As many as the server takes** Calls / second 416 24,934 calls in 60 s, 100 connections Notifications / second 40,498 2,503,300 received by 100 clients Delivery p50 574ms average 571 ms Delivery p99 785ms max 993 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.6 vCPU** · Redis **0.1 vCPU** · MongoDB **0.2 vCPU** · whole server busy **99 %** · load generator busy **36 %** autocannon · Inserts told to 100 clients, as many as the server takes am_ws_load · what the clients received ## With every client connected The same runs once more, with 26,484 clients connected and waiting : what a server which is full of WebSocket clients still does. | | No client, or 5,000 | 26,484 clients connected | |---|--:|--:| | A notification for one person, 1,000 a second : delivery p50 | 2.51 ms | **2.49 ms** | | … p99 | 3.82 ms | **7.48 ms** | | A notification for one person, as many as the server takes | 5,216 / s | **5,226 / s** | | Get all with both tokens, 100 connections (autocannon) | 2,095 req/s | **1,983 req/s** | | … latency p50 / p99 | 48 ms / 68 ms | **50 ms / 92 ms** | **Notification, 1,000 a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 10 connections Notifications / second 983 60,009 received by 26,484 clients Delivery p50 2.49ms average 2.60 ms Delivery p99 7.48ms max 25.4 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · whole server busy **29 %** · load generator busy **15 %** autocannon · A notification for one person, 1,000 a second, every client connected am_ws_load · what the clients received **Notification, as many as the server takes** Calls / second 5,297 317,793 calls in 60 s, 100 connections Notifications / second 5,226 317,890 received by 26,484 clients Delivery p50 18.5ms average 18.7 ms Delivery p99 30.2ms max 91.6 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.8 vCPU** · Redis **0.1 vCPU** · whole server busy **100 %** · load generator busy **37 %** autocannon · A notification for one person, as many as the server takes, every client connected am_ws_load · what the clients received **Get all with both tokens** Requests / second 1,983 118,976 requests in 60 s Latency p50 50ms average 49.92 ms Latency p99 92ms max 161 ms Errors 0 non-2xx, errors, timeouts (Server during this run) API Maker **0.5 vCPU** · Redis **0.0 vCPU** · MongoDB **0.3 vCPU** · whole server busy **100 %** · load generator busy **24 %** autocannon · get all with both tokens · 26,484 WebSocket clients connected ## A restart API Maker was restarted (`systemctl restart api_maker_be`) with 19,863 clients connected : the newest left first, down to 75 % of the 26,484 it held. Every client of a restarted server comes back within the same seconds and waits for its turn with its request in the kernel, about 4 KB each : a server needs that room. It takes what Redis keeps of them out first, then closes every client with the code `1001` (*Server is going away*) ; each client waits one to five seconds, as an application does, connects again with the same tokens and sends its `REGISTER` again. The server which comes back lets 256 clients in at a time and handles the messages of 256 at a time, the others wait for their turn : its memory comes back to what it was, not higher. Clients dropped 19,863 of 19,863 connected All back after 10.0s the restart itself : 2.5 s A client was away, p50 7.4s its own wait of 1 to 5 s counted A client was away, p99 9.1s the longest : 9.2 s After the restart, with the 19,863 clients back : API Maker 121 MB (126 MB before it), 314 MB of memory available. They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,000 arrived**, in 2.52 ms (p50) and 4.18 ms (p99). A client whose subscription had not come back with it would have been told nothing. ### Every client leaves at once At the end of the run, the 19,863 clients closed their connection in the same second, as when a network or a load balancer in front of the server goes. The server had closed every one of their sockets after **1.5 s**, and Redis held nothing of them any more after **2.6 s**. A socket is closed at once, and Redis is told behind it. ## Questions ### How many WebSocket connections can API Maker hold on 1 shared vCPU and 1 GB ? 26,484 clients were connected at the same time on this server, each with both tokens and a subscription of its own, with MongoDB, Redis and two sandboxes on the same machine. Memory is what ends first : a client costs about 8.6 KB of the server in all. ### How much memory does a WebSocket client cost ? About 8.6 KB : 3.3 KB in the API Maker process, 4.3 KB in the Linux kernel (its socket) and 1.0 KB in Redis (its subscription). Measured between 10,000 and 26,484 clients which wait, each connected with both tokens and one subscription. ### How many clients can connect each second ? 2,602 clients a second connected with both tokens, subscribed and left, 100 at a time ; 5,302 a second without a subscription. With a can user connect code on the event : 2,097 a second. ### How fast does a notification reach a client ? At 1,000 notifications a second, each for one person among 5,000 : 2.51 ms from the HTTP call to the client (p50), 3.82 ms for 99 % of them. With as many calls as the server takes : 5,216 notifications a second. ### Do connected WebSocket clients slow the APIs down ? Get all with both tokens answered 2,095 requests a second with no WebSocket client, and 1,983 with 26,484 clients connected and waiting. A client which waits costs memory ; its CPU is a ping a minute. --- # API Maker WebSocket benchmark : 2 vCPU, 4 GB RAM (Linode shared CPU) > API Maker WebSockets on 2 shared vCPUs, 4 GB (Linode) : 338,016 clients connected at once, 8 KB each, 4,041 new clients a second, with memory and outputs. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html WebSocket benchmark · Linode (Akamai Cloud) · Shared CPU · 14 October 2026 **2 vCPU, 4 GB RAM : 338,016 WebSocket clients connected at once.** API Maker 4.0.0 on a Linode 4 GB (g6-standard-2) : 2 shared vCPUs and 4 GB of RAM at $24 a month, its MongoDB and Redis on the same machine. A second server opened WebSocket clients, each with both tokens and a subscription of its own, until the memory of the server was full, while autocannon made the calls which notify them : every run 60 seconds, the memory and CPU of every part sampled each second. Clients connected 338,016 the memory was full : 499 MB left Memory per client 8.5KB API Maker 3.1 · kernel 4.3 · Redis 1.0 New clients / second 4,041 both tokens and a subscription · 9,504 without one Notification delivered in 1.45ms p50 at 1,000 a second · p99 3.15 ms ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Linode 4 GB (g6-standard-2), shared cpu, $24 / month | | CPU | AMD EPYC 7642 48-Core Processor, 2 shared vCPUs (KVM)
KVM guest, 1 thread per core · L1d 128 KiB (2 instances) · L2 1 MiB (2 instances) · L3 32 MiB (2 instances) · BogoMIPS 4599.99 | | Memory | 4 GB (3,915 MB usable), swap 4.3 GB (496 MB of Linode + 3.8 GB made by the installer) | | Disk, region | 80 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer : one worker thread per vCPU, up to 1,048,576 open files for the service (`LimitNOFILE`), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Network limits | as the installer sets them : 1,002,240 connections tracked by the firewall of Linux (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted (`net.core.somaxconn`). The memory of all its TCP connections together : raised by API Maker as the clients came, to 979 MB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) : on the same server. No other database runs | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 404 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default) | | Load generator | Dedicated 8 GB (g6-dedicated-4) : AMD EPYC 7642 48-Core Processor, 4 dedicated vCPUs, Ubuntu 24.04.4 LTS. The WebSocket clients : am_ws_load, a program in Rust made for these benchmarks, a socket and a task per client, from 21 addresses of the load generator. The HTTP calls : Node.js 24.21.0, autocannon 8.0.0 | | Network | A VLAN of the same data centre, round trip 0.35 ms (ping) | | Date | 14 October 2026, 03:17 to 03:54 UTC | Only what the run needs was running : API Maker and its two sandboxes, its MongoDB and its Redis. API Maker was restarted and the swap emptied before the run. How every number was taken : [How the WebSocket benchmarks are made](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html). The APIs of this server : [2 vCPU · 4 GB, API benchmark](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-2-vcpu-4gb.html). ## The data - **The clients** connect to `ws://:38246/?x-am-authorization=&x-am-user-authorization=` : the token of an API user, and the token of a person, a row of the `customers` table of the [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`) made by a DB token generator. API Maker checks both. - **A subscription** is one `REGISTER` for the custom WebSocket event `order-updates` with a condition of its own : `{ conditionType: 'RESPONSE', criteria: { recipientId: '' } }`. It is the way [one notification reaches one person](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html). - **A notification** for one person is 141 bytes ; a row of the dataset told to the clients of a table is 321 bytes. - **The tables** are the ones of the [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html#the-data), in MongoDB : ten rows of customers, ten columns each. ## Results at a glance **New clients per second** [Connect : the token of the API user](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#connect-1-token) · 9,799 [Connect : both tokens](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#connect-2-tokens) · 9,504 [Connect with both tokens and subscribe](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#subscribe) · 4,041 [Subscribe to an event with a can user connect code](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#can-user-connect) · the code ran in the server · 3,438 [Subscribe : the code reads the database](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#can-user-connect-database) · the code ran in the sandbox · 1,605 [Subscribe : the code reads the clock](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#can-user-connect-sandbox) · the code ran in the sandbox · 3,031 100 clients at a time connect, are let in and leave, for 60 seconds. **Notifications per second** [A notification for one person](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#one-person) · 7,657 calls / second · 7,562 [A broadcast](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#broadcast) · 105 calls / second · 103,387 [Rows inserted in a table](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html#insert) · 604 calls / second · 59,275 As many calls as the server takes : what the clients received each second. ## How many clients fit Clients connect 2,000 a second, level after level, each with both tokens and a subscription of its own ; at each level they wait 30 seconds while the server is sampled (the level the run stops at, 60). The run stopped adding clients at **338,016** : the memory of the server was full. 446 MB of its 3,916 MB were still counted as available, and Linux had moved 282 MB to the swap since the clients began to connect, to make that room : 164 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server). > Diagram : Clients connected and memory used during the run > > The run of this server, second after second : the WebSocket clients connected, up to 338,016, and the memory the server used, up to 3,463 MB of 3,915 MB. API Maker · MongoDB of API Maker · Redis · Sandboxes · Linux : its sockets, Docker, the rest · Available No client at rest 10,000 clients connected 25,000 clients connected 50,000 clients connected 100,000 clients connected 150,000 clients connected 200,000 clients connected 250,000 clients connected 300,000 clients connected 338,016 clients connected | Clients | API Maker | Redis | Kernel | MongoDB | Sandboxes | Server, used | Available | Swap | CPU busy | |---|--:|--:|--:|--:|--:|--:|--:|--:|--:| | None (at rest) | 110 | 1 | 201 | 123 | 51 | **802** | 3,114 | 0 | 1.4 % | | **10,000** | 149 | 12 | 270 | 157 | 246 | **1,124** | 2,792 | 0 | 1.3 % | | **25,000** | 202 | 27 | 310 | 195 | 246 | **1,275** | 2,641 | 0 | 1.4 % | | **50,000** | 275 | 52 | 412 | 192 | 246 | **1,462** | 2,454 | 0 | 2.1 % | | **100,000** | 437 | 102 | 626 | 192 | 246 | **1,866** | 2,050 | 0 | 2.6 % | | **150,000** | 599 | 157 | 838 | 192 | 246 | **2,267** | 1,649 | 0 | 3.7 % | | **200,000** | 751 | 204 | 1,049 | 192 | 246 | **2,652** | 1,264 | 0 | 6.8 % | | **250,000** | 892 | 250 | 1,264 | 191 | 246 | **3,030** | 886 | 0 | 8.5 % | | **300,000** | 1,020 | 313 | 1,473 | 170 | 183 | **3,333** | 583 | 118 | 9.5 % | | **338,016** | 1,110 | 347 | 1,635 | 117 | 91 | **3,417** | 499 | 310 | 9.7 % | Memory in MB. API Maker is the resident memory of its process ; Redis is the memory of its data (`used_memory`) ; the kernel of Linux keeps every socket and every tracked connection in its slab ; a container is counted the way `docker stats` counts it. CPU busy is the whole server while the clients wait : the server pings every client once a minute, and each answers. ### Memory when the server is full With **338,016 clients** connected and waiting, of the 3,916 MB of the server : | Part | At rest, no client | 338,016 clients | More | |---|--:|--:|--:| | **API Maker** (process) | 110 MB | **1,110 MB** | + 1,000 MB | | Redis (container) | 3 MB | **356 MB** | + 353 MB | | Linux kernel : sockets, tracked connections (slab) | 201 MB | **1,635 MB** | + 1,434 MB | | MongoDB of API Maker (container) | 123 MB | **117 MB** | − 6 MB | | Sandboxes (2 containers) | 51 MB | **91 MB** | + 41 MB | | **Whole server**, used | 802 MB | **3,417 MB** | + 2,615 MB | | Available | 3,114 MB | **499 MB** | | | Swap used | 0 MB | **310 MB** | | | Open files of API Maker | 28 | **338,044** | | | Keys of Redis · channels it listens on | 13 · 5 | **676,048 · 338,021** | | MongoDB and the sandboxes grew during the runs before this one (the inserts, the code of the events), not with the clients. ### What a client costs Between 100,000 and 250,000 clients (4 levels), each client more cost the server **8.5 KB** : | Where | Per client | What it is | |---|--:|---| | **API Maker** | **3.1 KB** | The client itself : its socket and the one task which reads it, its tokens and what they said, its subscription and the channel it is told on. | | Linux kernel | 4.3 KB | The TCP socket, and the entry of the connection in the table of the firewall (Docker makes Linux track every connection). | | Redis | 1.0 KB | The subscription : its key, its place in the list of its condition, and the channel API Maker listens on. | | **In all** | **8.5 KB** | 123,507 clients per GB of memory. | Measured over the levels at which nothing was in the swap. The memory the whole server had available went down by 7.9 KB per client : MongoDB, the sandboxes and the cache of files give some back while the clients take theirs. ## One more subscription, and a broadcast to everybody With 50,000 clients connected, every client sent a second `REGISTER`, for an event without a condition (`announcements`), 2,000 of them a second : 50,000 were taken in 25.0 s. They waited 30 seconds with two subscriptions each, were told 3 broadcasts, one call of the emit event WS API each, and took the subscription back with `UNREGISTER`. One subscription more 1.2KB per client : API Maker 0.5 KB · Redis 0.8 KB A broadcast to 50k clients 0.57s until the last client read it Half of them told after 363ms the first after 157 ms Clients told / second 87,821 one call, every client | Broadcast | Clients told | The call answered after | The first client | Half of them | 99 % of them | The last one | Clients told a second | |---|--:|--:|--:|--:|--:|--:|--:| | 1 | 50,000 of 50,000 | 0.77 s | 192 ms | 466 ms | 761 ms | **766 ms** | 65,278 | | 2 | 50,000 of 50,000 | 0.72 s | 167 ms | 424 ms | 715 ms | **721 ms** | 69,309 | | 3 | 50,000 of 50,000 | 0.57 s | 157 ms | 363 ms | 565 ms | **569 ms** | 87,821 | One call of the emit event WS API tells every client : API Maker asks Redis for the clients of the event, publishes the notification for each of them, and the server which holds a client sends it. The times are counted from the moment the call is written to the moment a client reads its notification. | Memory, 50,000 clients | One subscription each | Two subscriptions each | A subscription more, per client | |---|--:|--:|--:| | API Maker | 275 MB | 297 MB | 0.5 KB | | Redis (its data) | 52 MB | 88 MB | 0.8 KB | | Keys of Redis · channels | 100,016 · 50,005 | 150,017 · 100,005 | | | **Whole server**, less available | | | **1.2 KB** | ## New clients per second How many clients a second the server lets in : 100 clients at a time connect, are let in and leave, one after the other, for 60 seconds (after 5 seconds which are not counted). It is what a server faces when its clients all come back, after a deployment or a network cut. The times are counted from the start of the TCP connection. ### Connect : the token of the API user A client connects with `x-am-authorization` alone, is told `CONNECTED`, and leaves. API Maker checks the token of the API user and finds its groups : what every WebSocket client costs before it asks for anything. Clients / second 9,799 588,525 clients in 60 s, 100 at a time Let in after, p50 5.59ms connected 5.59 ms · TCP 0.22 ms Let in after, p99 10.8ms max 26.7 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.9 vCPU** · whole server busy **99 %** · load generator busy **66 %** am_ws_load · Connect : the token of the API user · 60 s ### Connect : both tokens A client connects with `x-am-authorization` and `x-am-user-authorization`, is told `CONNECTED`, and leaves. Both tokens are checked : the one of the API user, and the one of a person, made by the DB token generator of the account. Clients / second 9,504 570,797 clients in 60 s, 100 at a time Let in after, p50 5.77ms connected 5.77 ms · TCP 0.24 ms Let in after, p99 11.4ms max 27.5 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.9 vCPU** · whole server busy **99 %** · load generator busy **62 %** am_ws_load · Connect : both tokens · 60 s ### Connect with both tokens and subscribe The whole of what an application does : connect with both tokens, `CONNECTED`, one `REGISTER` for a custom WebSocket event with a condition of its own (`recipientId` : its user id), the answer, then leave. API Maker checks the groups and the auth provider of the event, keeps the subscription in Redis and listens on its channel ; when the client leaves, all of it is taken back. Clients / second 4,041 242,684 clients in 60 s, 100 at a time Let in after, p50 21.5ms connected 4.80 ms · TCP 0.21 ms Let in after, p99 31.2ms max 54.1 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.5 vCPU** · Redis **0.2 vCPU** · whole server busy **100 %** · load generator busy **37 %** am_ws_load · Connect with both tokens and subscribe · 60 s ### Subscribe to an event with a can user connect code The same, on an event whose *can user connect code* decides who may subscribe : it reads the person of `x-am-user-authorization` from `g.req.auth`. The code ran in the server itself (lean code, QuickJS). Clients / second 3,438 206,487 clients in 60 s, 100 at a time Let in after, p50 25.3ms connected 5.38 ms · TCP 0.21 ms Let in after, p99 37.0ms max 52.7 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.5 vCPU** · Redis **0.2 vCPU** · whole server busy **100 %** · load generator busy **33 %** am_ws_load · Subscribe to an event with a can user connect code · 60 s ### Subscribe : the code reads the database The same, with a can user connect code which also reads the person from the database (`g.sys.db.getAll` with a `find`) before it answers : one read of MongoDB for every subscription. The code ran in a sandbox of the account. Clients / second 1,605 96,421 clients in 60 s, 100 at a time Let in after, p50 56.5ms connected 8.26 ms · TCP 0.21 ms Let in after, p99 82.7ms max 124 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **0.7 vCPU** · Redis **0.1 vCPU** · MongoDB **0.4 vCPU** · sandboxes **0.7 vCPU** · whole server busy **100 %** · load generator busy **17 %** am_ws_load · Subscribe : the code reads the database · 60 s ### Subscribe : the code reads the clock The same, with a can user connect code which reads the time of the machine (`Date.now()`) : code which is not lean, so API Maker runs it in a sandbox of the account. The code ran in a sandbox of the account. Clients / second 3,031 182,012 clients in 60 s, 100 at a time Let in after, p50 29.6ms connected 5.06 ms · TCP 0.21 ms Let in after, p99 42.7ms max 59.9 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.3 vCPU** · Redis **0.2 vCPU** · sandboxes **0.3 vCPU** · whole server busy **100 %** · load generator busy **31 %** am_ws_load · Subscribe : the code reads the clock · 60 s ## Can user connect code An event of the WebSocket Events page can carry a *can user connect code* : API Maker runs it for every subscription to the event, with the tokens of the client in `g.req.auth` and the subscription in `g.req.eventData`, and lets the client subscribe when it returns `{ canConnect: true }`. Three codes were measured : one which reads the person of the token, one which also reads the database, one which reads the clock. **Reads the person of the token** **Can user connect code of the event checked-token : ran in the server** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { // The person of x-am-user-authorization : only somebody who signed in subscribes, from a country we serve. const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; return { canConnect: person.country === 'India', errorText: 'Not available in your country.' }; }; module.exports = main; ``` **Reads the database** **Can user connect code of the event checked-database : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // Still a customer ? One read of the database for every subscription. const rows = await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers', queryParams: { find: { customer_id: person.customer_id } } }); return { canConnect: rows.length === 1 && rows[0].country === 'India', errorText: 'Not a customer any more.' }; }; module.exports = main; ``` **Reads the clock** **Can user connect code of the event checked-sandbox : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // The time of the machine : this code runs in the sandbox of the account. const hour = new Date(Date.now()).getUTCHours(); return { canConnect: person.country === 'India' && hour >= 0, errorText: 'Not available in your country.' }; }; module.exports = main; ``` | Can user connect code | Runs in | Clients / second | Subscribed after, p50 | p99 | Against no code | |---|---|--:|--:|--:|--:| | No code | – | **4,041** | 21.5 ms | 31.2 ms | – | | Reads the person of the token | the server (QuickJS) | **3,438** | 25.3 ms | 37.0 ms | 15 % fewer | | Reads the person from the database | a sandbox of the account | **1,605** | 56.5 ms | 82.7 ms | 60 % fewer | | Reads the clock | a sandbox of the account | **3,031** | 29.6 ms | 42.7 ms | 25 % fewer | Lean code (it only reads what it is handed) runs in the server itself, with QuickJS, on the thread which serves the client. Code which needs more runs in a sandbox of the account : every subscription is then a round trip to the sandbox. ## Notifications With 10,000 clients connected, autocannon makes the HTTP calls which notify them, for 60 seconds, and the clients count what they receive and how late. Each kind of notification is measured twice : at a pace far under what the server takes, which shows how long a notification takes, and with no pace, which shows how many a second the server tells. *Delivery* is the time from the moment autocannon writes the request to the moment the client reads the notification : the HTTP call, API Maker, Redis, and the WebSocket. ### A notification for one person autocannon calls the [emit event WS API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-emit-event-ws-api.html) with both tokens ; every call names another one of the 10,000 connected clients (`recipientId`), which is the only one told. The clients measure how long each notification took from the moment its request was written. **1,000 calls a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 10 connections Notifications / second 991 60,010 received by 10,000 clients Delivery p50 1.45ms average 1.52 ms Delivery p99 3.15ms max 6.24 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · whole server busy **15 %** · load generator busy **13 %** autocannon · A notification for one person, 1,000 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 7,657 459,373 calls in 60 s, 100 connections Notifications / second 7,562 459,473 received by 10,000 clients Delivery p50 12.9ms average 12.9 ms Delivery p99 19.5ms max 37.9 ms Not delivered 0 0 calls failed (Server during this run) API Maker **1.6 vCPU** · Redis **0.1 vCPU** · whole server busy **99 %** · load generator busy **44 %** autocannon · A notification for one person, as many as the server takes am_ws_load · what the clients received ### A broadcast 1,000 more clients subscribe to an event without a condition : every call of the emit event WS API reaches all 1,000 of them. **5 calls a second** Calls / second (paced) 5 300 calls in 60 s, 1 connection Notifications / second 4,995 300,000 received by 1,000 clients Delivery p50 8.82ms average 9.18 ms Delivery p99 18.0ms max 23.5 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.1 vCPU** · Redis **0.0 vCPU** · whole server busy **8 %** · load generator busy **10 %** autocannon · A broadcast to 1,000 clients, 5 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 105 6,268 calls in 60 s, 10 connections Notifications / second 103,387 6,273,000 received by 1,000 clients Delivery p50 85.3ms average 85.6 ms Delivery p99 153ms max 228 ms Not delivered 0 0 calls failed (Server during this run) API Maker **1.8 vCPU** · Redis **0.1 vCPU** · whole server busy **98 %** · load generator busy **65 %** autocannon · A broadcast to 1,000 clients, as many as the server takes am_ws_load · what the clients received ### Rows inserted in a table 100 clients subscribe to the insert API of a table (`SCHEMA_POST_BULK_INSERT` on `inserts_public`, `getEventData: true`) ; autocannon inserts rows of the [dataset](https://apimaker.dev/json/benchmark_dataset.json) through the [insert API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html), and every row saved is told to each of the 100 clients, with its columns. **50 calls a second** Calls / second (paced) 50 3,000 calls in 60 s, 10 connections Notifications / second 4,931 301,000 received by 100 clients Delivery p50 25.3ms average 25.3 ms Delivery p99 44.4ms max 55.3 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.1 vCPU** · Redis **0.0 vCPU** · MongoDB **0.0 vCPU** · whole server busy **9 %** · load generator busy **11 %** autocannon · Inserts told to 100 clients, 50 inserts a second am_ws_load · what the clients received **As many as the server takes** Calls / second 604 36,218 calls in 60 s, 100 connections Notifications / second 59,275 3,631,600 received by 100 clients Delivery p50 562ms average 560 ms Delivery p99 716ms max 842 ms Not delivered 0 0 calls failed (Server during this run) API Maker **1.4 vCPU** · Redis **0.1 vCPU** · MongoDB **0.4 vCPU** · whole server busy **99 %** · load generator busy **39 %** autocannon · Inserts told to 100 clients, as many as the server takes am_ws_load · what the clients received ## With every client connected The same runs once more, with 338,016 clients connected and waiting : what a server which is full of WebSocket clients still does. | | No client, or 10,000 | 338,016 clients connected | |---|--:|--:| | A notification for one person, 1,000 a second : delivery p50 | 1.45 ms | **1.47 ms** | | … p99 | 3.15 ms | **3.27 ms** | | A notification for one person, as many as the server takes | 7,562 / s | **6,967 / s** | | Get all with both tokens, 100 connections (autocannon) | 3,379 req/s | **3,006 req/s** | | … latency p50 / p99 | 29 ms / 49 ms | **30 ms / 128 ms** | **Notification, 1,000 a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 10 connections Notifications / second 991 60,006 received by 338,016 clients Delivery p50 1.47ms average 1.56 ms Delivery p99 3.27ms max 26.1 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.3 vCPU** · Redis **0.0 vCPU** · whole server busy **22 %** · load generator busy **17 %** autocannon · A notification for one person, 1,000 a second, every client connected am_ws_load · what the clients received **Notification, as many as the server takes** Calls / second 7,055 423,236 calls in 60 s, 100 connections Notifications / second 6,967 423,336 received by 338,016 clients Delivery p50 13.0ms average 14.0 ms Delivery p99 43.4ms max 258 ms Not delivered 0 0 calls failed (Server during this run) API Maker **1.6 vCPU** · Redis **0.1 vCPU** · whole server busy **99 %** · load generator busy **50 %** autocannon · A notification for one person, as many as the server takes, every client connected am_ws_load · what the clients received **Get all with both tokens** Requests / second 3,006 180,301 requests in 60 s Latency p50 30ms average 32.77 ms Latency p99 128ms max 374 ms Errors 0 non-2xx, errors, timeouts (Server during this run) API Maker **1.1 vCPU** · Redis **0.0 vCPU** · MongoDB **0.6 vCPU** · whole server busy **100 %** · load generator busy **28 %** autocannon · get all with both tokens · 338,016 WebSocket clients connected ## A restart API Maker was restarted (`systemctl restart api_maker_be`) with 253,512 clients connected : the newest left first, down to 75 % of the 338,016 it held. Every client of a restarted server comes back within the same seconds and waits for its turn with its request in the kernel, about 4 KB each : a server needs that room. It takes what Redis keeps of them out first, then closes every client with the code `1001` (*Server is going away*) ; each client waits one to five seconds, as an application does, connects again with the same tokens and sends its `REGISTER` again. The server which comes back lets 256 clients in at a time and handles the messages of 256 at a time, the others wait for their turn : its memory comes back to what it was, not higher. Clients dropped 253,512 of 253,512 connected All back after 90.0s the restart itself : 18.7 s A client was away, p50 48.9s its own wait of 1 to 5 s counted A client was away, p99 78.2s the longest : 86.5 s After the restart, with the 253,512 clients back : API Maker 944 MB (1,110 MB before it), 1,075 MB of memory available. They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,000 arrived**, in 1.66 ms (p50) and 3.97 ms (p99). A client whose subscription had not come back with it would have been told nothing. ### Every client leaves at once At the end of the run, the 253,512 clients closed their connection in the same second, as when a network or a load balancer in front of the server goes. The server had closed every one of their sockets after **10.1 s**, and Redis held nothing of them any more after **13.8 s**. A socket is closed at once, and Redis is told behind it. ## Questions ### How many WebSocket connections can API Maker hold on 2 shared vCPUs and 4 GB ? 338,016 clients were connected at the same time on this server, each with both tokens and a subscription of its own, with MongoDB, Redis and two sandboxes on the same machine. Memory is what ends first : a client costs about 8.5 KB of the server in all. ### How much memory does a WebSocket client cost ? About 8.5 KB : 3.1 KB in the API Maker process, 4.3 KB in the Linux kernel (its socket) and 1.0 KB in Redis (its subscription). Measured between 100,000 and 250,000 clients which wait, each connected with both tokens and one subscription. ### How many clients can connect each second ? 4,041 clients a second connected with both tokens, subscribed and left, 100 at a time ; 9,504 a second without a subscription. With a can user connect code on the event : 3,438 a second. ### How fast does a notification reach a client ? At 1,000 notifications a second, each for one person among 10,000 : 1.45 ms from the HTTP call to the client (p50), 3.15 ms for 99 % of them. With as many calls as the server takes : 7,562 notifications a second. ### Do connected WebSocket clients slow the APIs down ? Get all with both tokens answered 3,379 requests a second with no WebSocket client, and 3,006 with 338,016 clients connected and waiting. A client which waits costs memory ; its CPU is a ping a minute. --- # API Maker WebSocket benchmark : 4 vCPU, 8 GB RAM (Linode shared CPU) > API Maker WebSockets on 4 shared vCPUs, 8 GB (Linode) : 801,972 clients connected at once, 9 KB each, 7,009 new clients a second, with memory and outputs. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html WebSocket benchmark · Linode (Akamai Cloud) · Shared CPU · 14 October 2026 **4 vCPU, 8 GB RAM : 801,972 WebSocket clients connected at once.** API Maker 4.0.0 on a Linode 8 GB (g6-standard-4) : 4 shared vCPUs and 8 GB of RAM at $48 a month, its MongoDB and Redis on the same machine. A second server opened WebSocket clients, each with both tokens and a subscription of its own, until the memory of the server was full, while autocannon made the calls which notify them : every run 60 seconds, the memory and CPU of every part sampled each second. Clients connected 801,972 the memory was full : 1,005 MB left Memory per client 8.7KB API Maker 3.3 · kernel 4.4 · Redis 1.1 New clients / second 7,009 both tokens and a subscription · 12,826 without one Notification delivered in 1.06ms p50 at 1,000 a second · p99 2.03 ms ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Linode 8 GB (g6-standard-4), shared cpu, $48 / month | | CPU | AMD EPYC 7642 48-Core Processor, 4 shared vCPUs (KVM)
KVM guest, 1 thread per core · L1d 256 KiB (4 instances) · L2 2 MiB (4 instances) · L3 64 MiB (4 instances) · BogoMIPS 4600.00 | | Memory | 8 GB (7,941 MB usable), swap 8.3 GB (496 MB of Linode + 7.8 GB made by the installer) | | Disk, region | 160 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer : one worker thread per vCPU, up to 2,032,896 open files for the service (`LimitNOFILE`), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Network limits | as the installer sets them : 2,032,896 connections tracked by the firewall of Linux (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted (`net.core.somaxconn`). The memory of all its TCP connections together : raised by API Maker as the clients came, to 1.9 GB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) : on the same server. No other database runs | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 404 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default) | | Load generator | Dedicated 16 GB (g6-dedicated-8) : AMD EPYC 7642 48-Core Processor, 8 dedicated vCPUs, Ubuntu 24.04.4 LTS. The WebSocket clients : am_ws_load, a program in Rust made for these benchmarks, a socket and a task per client, from 41 addresses of the load generator. The HTTP calls : Node.js 24.21.0, autocannon 8.0.0 | | Network | A VLAN of the same data centre, round trip 0.30 ms (ping) | | Date | 14 October 2026, 03:17 to 03:58 UTC | Only what the run needs was running : API Maker and its two sandboxes, its MongoDB and its Redis. API Maker was restarted and the swap emptied before the run. How every number was taken : [How the WebSocket benchmarks are made](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html). The APIs of this server : [4 vCPU · 8 GB, API benchmark](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-4-vcpu-8gb.html). ## The data - **The clients** connect to `ws://:38246/?x-am-authorization=&x-am-user-authorization=` : the token of an API user, and the token of a person, a row of the `customers` table of the [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`) made by a DB token generator. API Maker checks both. - **A subscription** is one `REGISTER` for the custom WebSocket event `order-updates` with a condition of its own : `{ conditionType: 'RESPONSE', criteria: { recipientId: '' } }`. It is the way [one notification reaches one person](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html). - **A notification** for one person is 141 bytes ; a row of the dataset told to the clients of a table is 321 bytes. - **The tables** are the ones of the [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html#the-data), in MongoDB : ten rows of customers, ten columns each. ## Results at a glance **New clients per second** [Connect : the token of the API user](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#connect-1-token) · 15,228 [Connect : both tokens](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#connect-2-tokens) · 12,826 [Connect with both tokens and subscribe](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#subscribe) · 7,009 [Subscribe to an event with a can user connect code](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#can-user-connect) · the code ran in the server · 5,916 [Subscribe : the code reads the database](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#can-user-connect-database) · the code ran in the sandbox · 2,735 [Subscribe : the code reads the clock](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#can-user-connect-sandbox) · the code ran in the sandbox · 5,243 100 clients at a time connect, are let in and leave, for 60 seconds. **Notifications per second** [A notification for one person](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#one-person) · 13,711 calls / second · 13,441 [A broadcast](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#broadcast) · 150 calls / second · 147,974 [Rows inserted in a table](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html#insert) · 932 calls / second · 92,279 As many calls as the server takes : what the clients received each second. ## How many clients fit Clients connect 4,000 a second, level after level, each with both tokens and a subscription of its own ; at each level they wait 30 seconds while the server is sampled (the level the run stops at, 60). The run stopped adding clients at **801,972** : the memory of the server was full. 996 MB of its 7,941 MB were still counted as available, and Linux had moved 606 MB to the swap since the clients began to connect, to make that room : 390 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server). > Diagram : Clients connected and memory used during the run > > The run of this server, second after second : the WebSocket clients connected, up to 801,972, and the memory the server used, up to 6,972 MB of 7,941 MB. API Maker · MongoDB of API Maker · Redis · Sandboxes · Linux : its sockets, Docker, the rest · Available No client at rest 10,000 clients connected 50,000 clients connected 100,000 clients connected 200,000 clients connected 300,000 clients connected 400,000 clients connected 500,000 clients connected 600,000 clients connected 700,000 clients connected 800,000 clients connected 801,972 clients connected | Clients | API Maker | Redis | Kernel | MongoDB | Sandboxes | Server, used | Available | Swap | CPU busy | |---|--:|--:|--:|--:|--:|--:|--:|--:|--:| | None (at rest) | 118 | 1 | 229 | 123 | 57 | **879** | 7,063 | 0 | 0.9 % | | **10,000** | 158 | 12 | 327 | 158 | 482 | **1,474** | 6,467 | 0 | 1.5 % | | **50,000** | 283 | 52 | 458 | 217 | 482 | **1,786** | 6,155 | 0 | 1.2 % | | **100,000** | 437 | 103 | 682 | 214 | 482 | **2,180** | 5,761 | 0 | 2.3 % | | **200,000** | 765 | 203 | 1,130 | 214 | 481 | **3,006** | 4,935 | 0 | 3.2 % | | **300,000** | 1,086 | 313 | 1,580 | 214 | 481 | **3,799** | 4,143 | 0 | 4.6 % | | **400,000** | 1,389 | 406 | 2,008 | 214 | 481 | **4,508** | 3,433 | 0 | 8.1 % | | **500,000** | 1,733 | 498 | 2,430 | 214 | 481 | **5,294** | 2,647 | 0 | 10.2 % | | **600,000** | 2,030 | 625 | 2,850 | 214 | 481 | **6,082** | 1,859 | 0 | 12.4 % | | **700,000** | 2,313 | 716 | 3,276 | 203 | 428 | **6,795** | 1,146 | 68 | 15.0 % | | **800,000** | 2,497 | 810 | 3,712 | 67 | 208 | **6,935** | 1,006 | 567 | 15.3 % | | **801,972** | 2,495 | 812 | 3,715 | 64 | 206 | **6,937** | 1,005 | 609 | 12.9 % | Memory in MB. API Maker is the resident memory of its process ; Redis is the memory of its data (`used_memory`) ; the kernel of Linux keeps every socket and every tracked connection in its slab ; a container is counted the way `docker stats` counts it. CPU busy is the whole server while the clients wait : the server pings every client once a minute, and each answers. ### Memory when the server is full With **801,972 clients** connected and waiting, of the 7,941 MB of the server : | Part | At rest, no client | 801,972 clients | More | |---|--:|--:|--:| | **API Maker** (process) | 118 MB | **2,495 MB** | + 2,377 MB | | Redis (container) | 3 MB | **808 MB** | + 805 MB | | Linux kernel : sockets, tracked connections (slab) | 229 MB | **3,715 MB** | + 3,486 MB | | MongoDB of API Maker (container) | 123 MB | **64 MB** | − 59 MB | | Sandboxes (2 containers) | 57 MB | **206 MB** | + 149 MB | | **Whole server**, used | 879 MB | **6,937 MB** | + 6,058 MB | | Available | 7,063 MB | **1,005 MB** | | | Swap used | 0 MB | **609 MB** | | | Open files of API Maker | 28 | **802,004** | | | Keys of Redis · channels it listens on | 13 · 5 | **1,603,960 · 801,977** | | MongoDB and the sandboxes grew during the runs before this one (the inserts, the code of the events), not with the clients. ### What a client costs Between 200,000 and 600,000 clients (5 levels), each client more cost the server **8.7 KB** : | Where | Per client | What it is | |---|--:|---| | **API Maker** | **3.3 KB** | The client itself : its socket and the one task which reads it, its tokens and what they said, its subscription and the channel it is told on. | | Linux kernel | 4.4 KB | The TCP socket, and the entry of the connection in the table of the firewall (Docker makes Linux track every connection). | | Redis | 1.1 KB | The subscription : its key, its place in the list of its condition, and the channel API Maker listens on. | | **In all** | **8.7 KB** | 120,250 clients per GB of memory. | Measured over the levels at which nothing was in the swap. The memory the whole server had available went down by 7.8 KB per client : MongoDB, the sandboxes and the cache of files give some back while the clients take theirs. ## One more subscription, and a broadcast to everybody With 100,000 clients connected, every client sent a second `REGISTER`, for an event without a condition (`announcements`), 4,000 of them a second : 100,000 were taken in 25.0 s. They waited 30 seconds with two subscriptions each, were told 3 broadcasts, one call of the emit event WS API each, and took the subscription back with `UNREGISTER`. One subscription more 1.2KB per client : API Maker 0.5 KB · Redis 0.8 KB A broadcast to 100k clients 1.09s until the last client read it Half of them told after 706ms the first after 358 ms Clients told / second 91,869 one call, every client | Broadcast | Clients told | The call answered after | The first client | Half of them | 99 % of them | The last one | Clients told a second | |---|--:|--:|--:|--:|--:|--:|--:| | 1 | 100,000 of 100,000 | 1.09 s | 358 ms | 706 ms | 1,079 ms | **1,089 ms** | 91,869 | | 2 | 100,000 of 100,000 | 1.25 s | 358 ms | 796 ms | 1,243 ms | **1,253 ms** | 79,784 | | 3 | 100,000 of 100,000 | 1.20 s | 323 ms | 781 ms | 1,184 ms | **1,195 ms** | 83,681 | One call of the emit event WS API tells every client : API Maker asks Redis for the clients of the event, publishes the notification for each of them, and the server which holds a client sends it. The times are counted from the moment the call is written to the moment a client reads its notification. | Memory, 100,000 clients | One subscription each | Two subscriptions each | A subscription more, per client | |---|--:|--:|--:| | API Maker | 437 MB | 484 MB | 0.5 KB | | Redis (its data) | 103 MB | 175 MB | 0.8 KB | | Keys of Redis · channels | 200,016 · 100,005 | 300,017 · 200,005 | | | **Whole server**, less available | | | **1.2 KB** | ## New clients per second How many clients a second the server lets in : 100 clients at a time connect, are let in and leave, one after the other, for 60 seconds (after 5 seconds which are not counted). It is what a server faces when its clients all come back, after a deployment or a network cut. The times are counted from the start of the TCP connection. ### Connect : the token of the API user A client connects with `x-am-authorization` alone, is told `CONNECTED`, and leaves. API Maker checks the token of the API user and finds its groups : what every WebSocket client costs before it asks for anything. Clients / second 15,228 914,609 clients in 60 s, 100 at a time Let in after, p50 3.89ms connected 3.89 ms · TCP 0.24 ms Let in after, p99 7.84ms max 43.4 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **3.7 vCPU** · MongoDB **0.0 vCPU** · whole server busy **96 %** · load generator busy **61 %** am_ws_load · Connect : the token of the API user · 60 s ### Connect : both tokens A client connects with `x-am-authorization` and `x-am-user-authorization`, is told `CONNECTED`, and leaves. Both tokens are checked : the one of the API user, and the one of a person, made by the DB token generator of the account. Clients / second 12,826 770,333 clients in 60 s, 100 at a time Let in after, p50 4.63ms connected 4.63 ms · TCP 0.23 ms Let in after, p99 9.04ms max 23.1 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **3.7 vCPU** · MongoDB **0.0 vCPU** · whole server busy **96 %** · load generator busy **48 %** am_ws_load · Connect : both tokens · 60 s ### Connect with both tokens and subscribe The whole of what an application does : connect with both tokens, `CONNECTED`, one `REGISTER` for a custom WebSocket event with a condition of its own (`recipientId` : its user id), the answer, then leave. API Maker checks the groups and the auth provider of the event, keeps the subscription in Redis and listens on its channel ; when the client leaves, all of it is taken back. Clients / second 7,009 420,960 clients in 60 s, 100 at a time Let in after, p50 12.5ms connected 2.97 ms · TCP 0.22 ms Let in after, p99 18.9ms max 30.3 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **3.0 vCPU** · Redis **0.3 vCPU** · whole server busy **95 %** · load generator busy **31 %** am_ws_load · Connect with both tokens and subscribe · 60 s ### Subscribe to an event with a can user connect code The same, on an event whose *can user connect code* decides who may subscribe : it reads the person of `x-am-user-authorization` from `g.req.auth`. The code ran in the server itself (lean code, QuickJS). Clients / second 5,916 355,319 clients in 60 s, 100 at a time Let in after, p50 14.9ms connected 3.34 ms · TCP 0.21 ms Let in after, p99 22.5ms max 36.8 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **3.1 vCPU** · Redis **0.3 vCPU** · whole server busy **97 %** · load generator busy **26 %** am_ws_load · Subscribe to an event with a can user connect code · 60 s ### Subscribe : the code reads the database The same, with a can user connect code which also reads the person from the database (`g.sys.db.getAll` with a `find`) before it answers : one read of MongoDB for every subscription. The code ran in a sandbox of the account. Clients / second 2,735 164,297 clients in 60 s, 100 at a time Let in after, p50 33.6ms connected 4.63 ms · TCP 0.21 ms Let in after, p99 52.0ms max 83.5 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.4 vCPU** · Redis **0.2 vCPU** · MongoDB **0.7 vCPU** · sandboxes **1.4 vCPU** · whole server busy **99 %** · load generator busy **11 %** am_ws_load · Subscribe : the code reads the database · 60 s ### Subscribe : the code reads the clock The same, with a can user connect code which reads the time of the machine (`Date.now()`) : code which is not lean, so API Maker runs it in a sandbox of the account. The code ran in a sandbox of the account. Clients / second 5,243 314,867 clients in 60 s, 100 at a time Let in after, p50 17.2ms connected 3.03 ms · TCP 0.21 ms Let in after, p99 26.5ms max 44.0 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **2.6 vCPU** · Redis **0.3 vCPU** · sandboxes **0.6 vCPU** · whole server busy **97 %** · load generator busy **23 %** am_ws_load · Subscribe : the code reads the clock · 60 s ## Can user connect code An event of the WebSocket Events page can carry a *can user connect code* : API Maker runs it for every subscription to the event, with the tokens of the client in `g.req.auth` and the subscription in `g.req.eventData`, and lets the client subscribe when it returns `{ canConnect: true }`. Three codes were measured : one which reads the person of the token, one which also reads the database, one which reads the clock. **Reads the person of the token** **Can user connect code of the event checked-token : ran in the server** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { // The person of x-am-user-authorization : only somebody who signed in subscribes, from a country we serve. const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; return { canConnect: person.country === 'India', errorText: 'Not available in your country.' }; }; module.exports = main; ``` **Reads the database** **Can user connect code of the event checked-database : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // Still a customer ? One read of the database for every subscription. const rows = await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers', queryParams: { find: { customer_id: person.customer_id } } }); return { canConnect: rows.length === 1 && rows[0].country === 'India', errorText: 'Not a customer any more.' }; }; module.exports = main; ``` **Reads the clock** **Can user connect code of the event checked-sandbox : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // The time of the machine : this code runs in the sandbox of the account. const hour = new Date(Date.now()).getUTCHours(); return { canConnect: person.country === 'India' && hour >= 0, errorText: 'Not available in your country.' }; }; module.exports = main; ``` | Can user connect code | Runs in | Clients / second | Subscribed after, p50 | p99 | Against no code | |---|---|--:|--:|--:|--:| | No code | – | **7,009** | 12.5 ms | 18.9 ms | – | | Reads the person of the token | the server (QuickJS) | **5,916** | 14.9 ms | 22.5 ms | 16 % fewer | | Reads the person from the database | a sandbox of the account | **2,735** | 33.6 ms | 52.0 ms | 61 % fewer | | Reads the clock | a sandbox of the account | **5,243** | 17.2 ms | 26.5 ms | 25 % fewer | Lean code (it only reads what it is handed) runs in the server itself, with QuickJS, on the thread which serves the client. Code which needs more runs in a sandbox of the account : every subscription is then a round trip to the sandbox. ## Notifications With 10,000 clients connected, autocannon makes the HTTP calls which notify them, for 60 seconds, and the clients count what they receive and how late. Each kind of notification is measured twice : at a pace far under what the server takes, which shows how long a notification takes, and with no pace, which shows how many a second the server tells. *Delivery* is the time from the moment autocannon writes the request to the moment the client reads the notification : the HTTP call, API Maker, Redis, and the WebSocket. ### A notification for one person autocannon calls the [emit event WS API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-emit-event-ws-api.html) with both tokens ; every call names another one of the 10,000 connected clients (`recipientId`), which is the only one told. The clients measure how long each notification took from the moment its request was written. **1,000 calls a second** Calls / second (paced) 1,000 60,003 calls in 60 s, 10 connections Notifications / second 983 60,013 received by 10,000 clients Delivery p50 1.06ms average 1.11 ms Delivery p99 2.03ms max 8.62 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.3 vCPU** · Redis **0.0 vCPU** · whole server busy **10 %** · load generator busy **6 %** autocannon · A notification for one person, 1,000 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 13,711 822,630 calls in 60 s, 100 connections Notifications / second 13,441 822,727 received by 10,000 clients Delivery p50 7.07ms average 7.12 ms Delivery p99 10.9ms max 22.1 ms Not delivered 0 0 calls failed (Server during this run) API Maker **3.4 vCPU** · Redis **0.2 vCPU** · whole server busy **96 %** · load generator busy **31 %** autocannon · A notification for one person, as many as the server takes am_ws_load · what the clients received ### A broadcast 1,000 more clients subscribe to an event without a condition : every call of the emit event WS API reaches all 1,000 of them. **5 calls a second** Calls / second (paced) 5 300 calls in 60 s, 1 connection Notifications / second 4,997 300,000 received by 1,000 clients Delivery p50 7.56ms average 8.06 ms Delivery p99 16.4ms max 23.2 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.1 vCPU** · Redis **0.0 vCPU** · whole server busy **4 %** · load generator busy **5 %** autocannon · A broadcast to 1,000 clients, 5 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 150 8,977 calls in 60 s, 10 connections Notifications / second 147,974 8,985,000 received by 1,000 clients Delivery p50 58.5ms average 58.5 ms Delivery p99 93.6ms max 134 ms Not delivered 0 0 calls failed (Server during this run) API Maker **3.4 vCPU** · Redis **0.2 vCPU** · whole server busy **94 %** · load generator busy **47 %** autocannon · A broadcast to 1,000 clients, as many as the server takes am_ws_load · what the clients received ### Rows inserted in a table 100 clients subscribe to the insert API of a table (`SCHEMA_POST_BULK_INSERT` on `inserts_public`, `getEventData: true`) ; autocannon inserts rows of the [dataset](https://apimaker.dev/json/benchmark_dataset.json) through the [insert API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html), and every row saved is told to each of the 100 clients, with its columns. **50 calls a second** Calls / second (paced) 50 3,002 calls in 60 s, 10 connections Notifications / second 4,933 301,100 received by 100 clients Delivery p50 18.1ms average 18.1 ms Delivery p99 30.0ms max 39.1 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · MongoDB **0.0 vCPU** · whole server busy **6 %** · load generator busy **5 %** autocannon · Inserts told to 100 clients, 50 inserts a second am_ws_load · what the clients received **As many as the server takes** Calls / second 932 55,919 calls in 60 s, 100 connections Notifications / second 92,279 5,601,600 received by 100 clients Delivery p50 370ms average 370 ms Delivery p99 448ms max 518 ms Not delivered 0 0 calls failed (Server during this run) API Maker **2.7 vCPU** · Redis **0.1 vCPU** · MongoDB **0.6 vCPU** · whole server busy **95 %** · load generator busy **37 %** autocannon · Inserts told to 100 clients, as many as the server takes am_ws_load · what the clients received ## With every client connected The same runs once more, with 801,972 clients connected and waiting : what a server which is full of WebSocket clients still does. | | No client, or 10,000 | 801,972 clients connected | |---|--:|--:| | A notification for one person, 1,000 a second : delivery p50 | 1.06 ms | **1.22 ms** | | … p99 | 2.03 ms | **2.44 ms** | | A notification for one person, as many as the server takes | 13,441 / s | **10,799 / s** | | Get all with both tokens, 100 connections (autocannon) | 6,072 req/s | **4,767 req/s** | | … latency p50 / p99 | 16 ms / 30 ms | **18 ms / 105 ms** | **Notification, 1,000 a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 10 connections Notifications / second 983 60,010 received by 801,972 clients Delivery p50 1.22ms average 1.27 ms Delivery p99 2.44ms max 6.45 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.8 vCPU** · Redis **0.0 vCPU** · whole server busy **25 %** · load generator busy **13 %** autocannon · A notification for one person, 1,000 a second, every client connected am_ws_load · what the clients received **Notification, as many as the server takes** Calls / second 10,925 655,468 calls in 60 s, 100 connections Notifications / second 10,799 655,568 received by 801,972 clients Delivery p50 7.66ms average 8.97 ms Delivery p99 43.7ms max 173 ms Not delivered 0 0 calls failed (Server during this run) API Maker **3.4 vCPU** · Redis **0.2 vCPU** · whole server busy **97 %** · load generator busy **41 %** autocannon · A notification for one person, as many as the server takes, every client connected am_ws_load · what the clients received **Get all with both tokens** Requests / second 4,767 285,971 requests in 60 s Latency p50 18ms average 20.48 ms Latency p99 105ms max 296 ms Errors 0 non-2xx, errors, timeouts (Server during this run) API Maker **2.3 vCPU** · Redis **0.2 vCPU** · MongoDB **1.1 vCPU** · whole server busy **99 %** · load generator busy **23 %** autocannon · get all with both tokens · 801,972 WebSocket clients connected ## A restart API Maker was restarted (`systemctl restart api_maker_be`) with 601,479 clients connected : the newest left first, down to 75 % of the 801,972 it held. Every client of a restarted server comes back within the same seconds and waits for its turn with its request in the kernel, about 4 KB each : a server needs that room. It takes what Redis keeps of them out first, then closes every client with the code `1001` (*Server is going away*) ; each client waits one to five seconds, as an application does, connects again with the same tokens and sends its `REGISTER` again. The server which comes back lets 256 clients in at a time and handles the messages of 256 at a time, the others wait for their turn : its memory comes back to what it was, not higher. Clients dropped 601,479 of 601,479 connected All back after 189.1s the restart itself : 45.7 s A client was away, p50 76.7s its own wait of 1 to 5 s counted A client was away, p99 173.1s the longest : 177 s After the restart, with the 601,479 clients back : API Maker 2,055 MB (2,495 MB before it), 2,174 MB of memory available. They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,005 arrived**, in 1.27 ms (p50) and 2.66 ms (p99). A client whose subscription had not come back with it would have been told nothing. ### Every client leaves at once At the end of the run, the 601,479 clients closed their connection in the same second, as when a network or a load balancer in front of the server goes. The server had closed every one of their sockets after **18.0 s**, and Redis held nothing of them any more after **26.9 s**. A socket is closed at once, and Redis is told behind it. ## Questions ### How many WebSocket connections can API Maker hold on 4 shared vCPUs and 8 GB ? 801,972 clients were connected at the same time on this server, each with both tokens and a subscription of its own, with MongoDB, Redis and two sandboxes on the same machine. Memory is what ends first : a client costs about 8.7 KB of the server in all. ### How much memory does a WebSocket client cost ? About 8.7 KB : 3.3 KB in the API Maker process, 4.4 KB in the Linux kernel (its socket) and 1.1 KB in Redis (its subscription). Measured between 200,000 and 600,000 clients which wait, each connected with both tokens and one subscription. ### How many clients can connect each second ? 7,009 clients a second connected with both tokens, subscribed and left, 100 at a time ; 12,826 a second without a subscription. With a can user connect code on the event : 5,916 a second. ### How fast does a notification reach a client ? At 1,000 notifications a second, each for one person among 10,000 : 1.06 ms from the HTTP call to the client (p50), 2.03 ms for 99 % of them. With as many calls as the server takes : 13,441 notifications a second. ### Do connected WebSocket clients slow the APIs down ? Get all with both tokens answered 6,072 requests a second with no WebSocket client, and 4,767 with 801,972 clients connected and waiting. A client which waits costs memory ; its CPU is a ping a minute. --- # API Maker WebSocket benchmark : 8 vCPU, 32 GB RAM (Linode shared CPU) > API Maker WebSockets on 8 shared vCPUs, 32 GB (Linode) : 3,662,564 clients connected at once, 9 KB each, 10,939 new clients a second, with memory and outputs. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html WebSocket benchmark · Linode (Akamai Cloud) · Shared CPU · 14 October 2026 **8 vCPU, 32 GB RAM : 3,662,564 WebSocket clients connected at once.** API Maker 4.0.0 on a Linode 32 GB (g6-standard-8) : 8 shared vCPUs and 32 GB of RAM at $192 a month, its MongoDB and Redis on the same machine. A second server opened WebSocket clients, each with both tokens and a subscription of its own, until the memory of the server was full, while autocannon made the calls which notify them : every run 60 seconds, the memory and CPU of every part sampled each second. Clients connected 3,662,564 the memory was full : 4,478 MB left Memory per client 8.8KB API Maker 3.2 · kernel 4.5 · Redis 1.1 New clients / second 10,939 both tokens and a subscription · 24,719 without one Notification delivered in 0.94ms p50 at 1,000 a second · p99 6.54 ms ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Linode 32 GB (g6-standard-8), shared cpu, $192 / month | | CPU | AMD EPYC 7642 48-Core Processor, 8 shared vCPUs (KVM)
KVM guest, 1 thread per core · L1d 512 KiB (8 instances) · L2 4 MiB (8 instances) · L3 128 MiB (8 instances) · BogoMIPS 4599.99 | | Memory | 32 GB (32,095 MB usable), swap 8.5 GB (496 MB of Linode + 8 GB made by the installer) | | Disk, region | 640 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer : one worker thread per vCPU, up to 8,216,320 open files for the service (`LimitNOFILE`), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Network limits | as the installer sets them : 8,216,320 connections tracked by the firewall of Linux (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted (`net.core.somaxconn`). The memory of all its TCP connections together : raised by API Maker as the clients came, to 7.8 GB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) : on the same server. No other database runs | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 404 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default) | | Load generator | Dedicated 64 GB (g6-dedicated-32) : AMD EPYC 7642 48-Core Processor, 32 dedicated vCPUs, Ubuntu 24.04.4 LTS. The WebSocket clients : am_ws_load, a program in Rust made for these benchmarks, a socket and a task per client, from 151 addresses of the load generator. The HTTP calls : Node.js 24.21.0, autocannon 8.0.0 | | Network | A VLAN of the same data centre, round trip 1.89 ms (ping) | | Date | 14 October 2026, 03:18 to 04:26 UTC | Only what the run needs was running : API Maker and its two sandboxes, its MongoDB and its Redis. API Maker was restarted and the swap emptied before the run. How every number was taken : [How the WebSocket benchmarks are made](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html). The APIs of this server : [8 vCPU · 32 GB, API benchmark](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html). ## The data - **The clients** connect to `ws://:38246/?x-am-authorization=&x-am-user-authorization=` : the token of an API user, and the token of a person, a row of the `customers` table of the [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`) made by a DB token generator. API Maker checks both. - **A subscription** is one `REGISTER` for the custom WebSocket event `order-updates` with a condition of its own : `{ conditionType: 'RESPONSE', criteria: { recipientId: '' } }`. It is the way [one notification reaches one person](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html). - **A notification** for one person is 141 bytes ; a row of the dataset told to the clients of a table is 321 bytes. - **The tables** are the ones of the [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html#the-data), in MongoDB : ten rows of customers, ten columns each. ## Results at a glance **New clients per second** [Connect : the token of the API user](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#connect-1-token) · 24,511 [Connect : both tokens](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#connect-2-tokens) · 24,719 [Connect with both tokens and subscribe](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#subscribe) · 10,939 [Subscribe to an event with a can user connect code](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#can-user-connect) · the code ran in the server · 9,280 [Subscribe : the code reads the database](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#can-user-connect-database) · the code ran in the sandbox · 4,381 [Subscribe : the code reads the clock](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#can-user-connect-sandbox) · the code ran in the sandbox · 7,741 100 clients at a time connect, are let in and leave, for 60 seconds. **Notifications per second** [A notification for one person](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#one-person) · 21,628 calls / second · 21,208 [A broadcast](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#broadcast) · 199 calls / second · 196,995 [Rows inserted in a table](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#insert) · 1,396 calls / second · 136,942 As many calls as the server takes : what the clients received each second. ## How many clients fit Clients connect 8,000 a second, level after level, each with both tokens and a subscription of its own ; at each level they wait 30 seconds while the server is sampled (the level the run stops at, 60). The run stopped adding clients at **3,662,564** : the memory of the server was full. 4,129 MB of its 32,096 MB were still counted as available, and Linux had moved 2,537 MB to the swap since the clients began to connect, to make that room : 1,592 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server). > Diagram : Clients connected and memory used during the run > > The run of this server, second after second : the WebSocket clients connected, up to 3,662,564, and the memory the server used, up to 28,325 MB of 32,095 MB. API Maker · MongoDB of API Maker · Redis · Sandboxes · Linux : its sockets, Docker, the rest · Available No client at rest 10,000 clients connected 250,000 clients connected 500,000 clients connected 1,000,000 clients connected 1,500,000 clients connected 2,000,000 clients connected 2,500,000 clients connected 3,000,000 clients connected 3,500,000 clients connected 3,662,564 clients connected | Clients | API Maker | Redis | Kernel | MongoDB | Sandboxes | Server, used | Available | Swap | CPU busy | |---|--:|--:|--:|--:|--:|--:|--:|--:|--:| | None (at rest) | 121 | 1 | 242 | 124 | 57 | **1,083** | 31,013 | 0 | 0.6 % | | **10,000** | 163 | 12 | 379 | 162 | 904 | **2,123** | 29,973 | 0 | 1.0 % | | **250,000** | 938 | 250 | 1,369 | 244 | 906 | **4,009** | 28,087 | 0 | 2.5 % | | **500,000** | 1,728 | 498 | 2,485 | 243 | 906 | **6,001** | 26,095 | 0 | 6.1 % | | **1,000,000** | 3,395 | 996 | 4,709 | 243 | 906 | **10,116** | 21,980 | 0 | 11.3 % | | **1,500,000** | 4,923 | 1,525 | 6,942 | 243 | 906 | **14,082** | 18,014 | 0 | 20.7 % | | **2,000,000** | 6,600 | 1,990 | 9,174 | 243 | 906 | **18,249** | 13,847 | 0 | 25.6 % | | **2,500,000** | 8,129 | 2,591 | 11,398 | 243 | 906 | **22,097** | 9,999 | 0 | 26.3 % | | **3,000,000** | 9,657 | 3,048 | 13,564 | 243 | 905 | **25,904** | 6,191 | 0 | 36.2 % | | **3,500,000** | 10,594 | 3,505 | 15,732 | 108 | 356 | **27,815** | 4,281 | 1,431 | 46.1 % | | **3,662,564** | 10,196 | 3,658 | 16,443 | 61 | 245 | **27,618** | 4,478 | 2,691 | 50.6 % | Memory in MB. API Maker is the resident memory of its process ; Redis is the memory of its data (`used_memory`) ; the kernel of Linux keeps every socket and every tracked connection in its slab ; a container is counted the way `docker stats` counts it. CPU busy is the whole server while the clients wait : the server pings every client once a minute, and each answers. ### Memory when the server is full With **3,662,564 clients** connected and waiting, of the 32,096 MB of the server : | Part | At rest, no client | 3,662,564 clients | More | |---|--:|--:|--:| | **API Maker** (process) | 121 MB | **10,196 MB** | + 10,075 MB | | Redis (container) | 3 MB | **3,533 MB** | + 3,530 MB | | Linux kernel : sockets, tracked connections (slab) | 242 MB | **16,443 MB** | + 16,201 MB | | MongoDB of API Maker (container) | 124 MB | **61 MB** | − 63 MB | | Sandboxes (2 containers) | 57 MB | **245 MB** | + 188 MB | | **Whole server**, used | 1,083 MB | **27,618 MB** | + 26,535 MB | | Available | 31,013 MB | **4,478 MB** | | | Swap used | 0 MB | **2,691 MB** | | | Open files of API Maker | 28 | **3,662,604** | | | Keys of Redis · channels it listens on | 13 · 5 | **7,325,144 · 3,662,569** | | MongoDB and the sandboxes grew during the runs before this one (the inserts, the code of the events), not with the clients. ### What a client costs Between 1,000,000 and 3,000,000 clients (5 levels), each client more cost the server **8.8 KB** : | Where | Per client | What it is | |---|--:|---| | **API Maker** | **3.2 KB** | The client itself : its socket and the one task which reads it, its tokens and what they said, its subscription and the channel it is told on. | | Linux kernel | 4.5 KB | The TCP socket, and the entry of the connection in the table of the firewall (Docker makes Linux track every connection). | | Redis | 1.1 KB | The subscription : its key, its place in the list of its condition, and the channel API Maker listens on. | | **In all** | **8.8 KB** | 118,483 clients per GB of memory. | Measured over the levels at which nothing was in the swap. The memory the whole server had available went down by 8.1 KB per client : MongoDB, the sandboxes and the cache of files give some back while the clients take theirs. ## One more subscription, and a broadcast to everybody With 500,000 clients connected, every client sent a second `REGISTER`, for an event without a condition (`announcements`), 8,000 of them a second : 500,000 were taken in 62.5 s. They waited 30 seconds with two subscriptions each, were told 3 broadcasts, one call of the emit event WS API each, and took the subscription back with `UNREGISTER`. One subscription more 1.2KB per client : API Maker 0.5 KB · Redis 0.7 KB A broadcast to 500k clients 5.63s until the last client read it Half of them told after 4,256ms the first after 2,574 ms Clients told / second 88,778 one call, every client | Broadcast | Clients told | The call answered after | The first client | Half of them | 99 % of them | The last one | Clients told a second | |---|--:|--:|--:|--:|--:|--:|--:| | 1 | 500,000 of 500,000 | 6.69 s | 3,361 ms | 4,932 ms | 6,652 ms | **6,685 ms** | 74,798 | | 2 | 500,000 of 500,000 | 5.63 s | 2,574 ms | 4,256 ms | 5,603 ms | **5,632 ms** | 88,778 | | 3 | 500,000 of 500,000 | 6.06 s | 2,284 ms | 3,686 ms | 6,013 ms | **6,058 ms** | 82,536 | One call of the emit event WS API tells every client : API Maker asks Redis for the clients of the event, publishes the notification for each of them, and the server which holds a client sends it. The times are counted from the moment the call is written to the moment a client reads its notification. | Memory, 500,000 clients | One subscription each | Two subscriptions each | A subscription more, per client | |---|--:|--:|--:| | API Maker | 1,728 MB | 1,974 MB | 0.5 KB | | Redis (its data) | 498 MB | 851 MB | 0.7 KB | | Keys of Redis · channels | 1,000,016 · 500,005 | 1,500,017 · 1,000,005 | | | **Whole server**, less available | | | **1.2 KB** | ## New clients per second How many clients a second the server lets in : 100 clients at a time connect, are let in and leave, one after the other, for 60 seconds (after 5 seconds which are not counted). It is what a server faces when its clients all come back, after a deployment or a network cut. The times are counted from the start of the TCP connection. ### Connect : the token of the API user A client connects with `x-am-authorization` alone, is told `CONNECTED`, and leaves. API Maker checks the token of the API user and finds its groups : what every WebSocket client costs before it asks for anything. Clients / second 24,511 1,472,138 clients in 60 s, 100 at a time Let in after, p50 2.50ms connected 2.50 ms · TCP 0.24 ms Let in after, p99 6.24ms max 38.6 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **6.7 vCPU** · MongoDB **0.0 vCPU** · whole server busy **89 %** · load generator busy **17 %** am_ws_load · Connect : the token of the API user · 60 s ### Connect : both tokens A client connects with `x-am-authorization` and `x-am-user-authorization`, is told `CONNECTED`, and leaves. Both tokens are checked : the one of the API user, and the one of a person, made by the DB token generator of the account. Clients / second 24,719 1,484,603 clients in 60 s, 100 at a time Let in after, p50 2.53ms connected 2.53 ms · TCP 0.24 ms Let in after, p99 4.72ms max 21.3 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **7.0 vCPU** · MongoDB **0.0 vCPU** · whole server busy **92 %** · load generator busy **20 %** am_ws_load · Connect : both tokens · 60 s ### Connect with both tokens and subscribe The whole of what an application does : connect with both tokens, `CONNECTED`, one `REGISTER` for a custom WebSocket event with a condition of its own (`recipientId` : its user id), the answer, then leave. API Maker checks the groups and the auth provider of the event, keeps the subscription in Redis and listens on its channel ; when the client leaves, all of it is taken back. Clients / second 10,939 656,986 clients in 60 s, 100 at a time Let in after, p50 7.91ms connected 2.10 ms · TCP 0.23 ms Let in after, p99 13.4ms max 54.7 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **5.2 vCPU** · Redis **0.5 vCPU** · whole server busy **80 %** · load generator busy **9 %** am_ws_load · Connect with both tokens and subscribe · 60 s ### Subscribe to an event with a can user connect code The same, on an event whose *can user connect code* decides who may subscribe : it reads the person of `x-am-user-authorization` from `g.req.auth`. The code ran in the server itself (lean code, QuickJS). Clients / second 9,280 557,330 clients in 60 s, 100 at a time Let in after, p50 9.35ms connected 2.35 ms · TCP 0.23 ms Let in after, p99 16.9ms max 60.5 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **5.5 vCPU** · Redis **0.4 vCPU** · whole server busy **83 %** · load generator busy **8 %** am_ws_load · Subscribe to an event with a can user connect code · 60 s ### Subscribe : the code reads the database The same, with a can user connect code which also reads the person from the database (`g.sys.db.getAll` with a `find`) before it answers : one read of MongoDB for every subscription. The code ran in a sandbox of the account. Clients / second 4,381 263,133 clients in 60 s, 100 at a time Let in after, p50 21.0ms connected 2.84 ms · TCP 0.23 ms Let in after, p99 35.9ms max 74.3 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **2.6 vCPU** · Redis **0.2 vCPU** · MongoDB **1.3 vCPU** · sandboxes **2.8 vCPU** · whole server busy **92 %** · load generator busy **4 %** am_ws_load · Subscribe : the code reads the database · 60 s ### Subscribe : the code reads the clock The same, with a can user connect code which reads the time of the machine (`Date.now()`) : code which is not lean, so API Maker runs it in a sandbox of the account. The code ran in a sandbox of the account. Clients / second 7,741 464,920 clients in 60 s, 100 at a time Let in after, p50 11.3ms connected 2.10 ms · TCP 0.23 ms Let in after, p99 25.6ms max 66.5 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **4.6 vCPU** · Redis **0.4 vCPU** · MongoDB **0.0 vCPU** · sandboxes **1.3 vCPU** · whole server busy **88 %** · load generator busy **6 %** am_ws_load · Subscribe : the code reads the clock · 60 s ## Can user connect code An event of the WebSocket Events page can carry a *can user connect code* : API Maker runs it for every subscription to the event, with the tokens of the client in `g.req.auth` and the subscription in `g.req.eventData`, and lets the client subscribe when it returns `{ canConnect: true }`. Three codes were measured : one which reads the person of the token, one which also reads the database, one which reads the clock. **Reads the person of the token** **Can user connect code of the event checked-token : ran in the server** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { // The person of x-am-user-authorization : only somebody who signed in subscribes, from a country we serve. const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; return { canConnect: person.country === 'India', errorText: 'Not available in your country.' }; }; module.exports = main; ``` **Reads the database** **Can user connect code of the event checked-database : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // Still a customer ? One read of the database for every subscription. const rows = await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers', queryParams: { find: { customer_id: person.customer_id } } }); return { canConnect: rows.length === 1 && rows[0].country === 'India', errorText: 'Not a customer any more.' }; }; module.exports = main; ``` **Reads the clock** **Can user connect code of the event checked-sandbox : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // The time of the machine : this code runs in the sandbox of the account. const hour = new Date(Date.now()).getUTCHours(); return { canConnect: person.country === 'India' && hour >= 0, errorText: 'Not available in your country.' }; }; module.exports = main; ``` | Can user connect code | Runs in | Clients / second | Subscribed after, p50 | p99 | Against no code | |---|---|--:|--:|--:|--:| | No code | – | **10,939** | 7.91 ms | 13.4 ms | – | | Reads the person of the token | the server (QuickJS) | **9,280** | 9.35 ms | 16.9 ms | 15 % fewer | | Reads the person from the database | a sandbox of the account | **4,381** | 21.0 ms | 35.9 ms | 60 % fewer | | Reads the clock | a sandbox of the account | **7,741** | 11.3 ms | 25.6 ms | 29 % fewer | Lean code (it only reads what it is handed) runs in the server itself, with QuickJS, on the thread which serves the client. Code which needs more runs in a sandbox of the account : every subscription is then a round trip to the sandbox. ## Notifications With 10,000 clients connected, autocannon makes the HTTP calls which notify them, for 60 seconds, and the clients count what they receive and how late. Each kind of notification is measured twice : at a pace far under what the server takes, which shows how long a notification takes, and with no pace, which shows how many a second the server tells. *Delivery* is the time from the moment autocannon writes the request to the moment the client reads the notification : the HTTP call, API Maker, Redis, and the WebSocket. ### A notification for one person autocannon calls the [emit event WS API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-emit-event-ws-api.html) with both tokens ; every call names another one of the 10,000 connected clients (`recipientId`), which is the only one told. The clients measure how long each notification took from the moment its request was written. **1,000 calls a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 10 connections Notifications / second 983 60,010 received by 10,000 clients Delivery p50 0.94ms average 1.14 ms Delivery p99 6.54ms max 21.3 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.4 vCPU** · Redis **0.1 vCPU** · whole server busy **7 %** · load generator busy **1 %** autocannon · A notification for one person, 1,000 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 21,628 1,297,651 calls in 60 s, 100 connections Notifications / second 21,208 1,297,750 received by 10,000 clients Delivery p50 4.33ms average 4.47 ms Delivery p99 7.77ms max 45.8 ms Not delivered 0 0 calls failed (Server during this run) API Maker **6.4 vCPU** · Redis **0.3 vCPU** · whole server busy **88 %** · load generator busy **11 %** autocannon · A notification for one person, as many as the server takes am_ws_load · what the clients received ### A broadcast 1,000 more clients subscribe to an event without a condition : every call of the emit event WS API reaches all 1,000 of them. **5 calls a second** Calls / second (paced) 5 300 calls in 60 s, 1 connection Notifications / second 4,994 300,000 received by 1,000 clients Delivery p50 8.70ms average 9.36 ms Delivery p99 19.9ms max 43.6 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · whole server busy **3 %** · load generator busy **4 %** autocannon · A broadcast to 1,000 clients, 5 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 199 11,947 calls in 60 s, 10 connections Notifications / second 196,995 11,957,000 received by 1,000 clients Delivery p50 40.4ms average 41.0 ms Delivery p99 69.4ms max 152 ms Not delivered 0 0 calls failed (Server during this run) API Maker **6.2 vCPU** · Redis **0.3 vCPU** · whole server busy **86 %** · load generator busy **14 %** autocannon · A broadcast to 1,000 clients, as many as the server takes am_ws_load · what the clients received ### Rows inserted in a table 100 clients subscribe to the insert API of a table (`SCHEMA_POST_BULK_INSERT` on `inserts_public`, `getEventData: true`) ; autocannon inserts rows of the [dataset](https://apimaker.dev/json/benchmark_dataset.json) through the [insert API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html), and every row saved is told to each of the 100 clients, with its columns. **50 calls a second** Calls / second (paced) 50 3,000 calls in 60 s, 10 connections Notifications / second 4,930 301,000 received by 100 clients Delivery p50 13.4ms average 14.1 ms Delivery p99 35.5ms max 50.0 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · MongoDB **0.1 vCPU** · whole server busy **4 %** · load generator busy **5 %** autocannon · Inserts told to 100 clients, 50 inserts a second am_ws_load · what the clients received **As many as the server takes** Calls / second 1,396 83,727 calls in 60 s, 100 connections Notifications / second 136,942 8,382,200 received by 100 clients Delivery p50 246ms average 248 ms Delivery p99 332ms max 538 ms Not delivered 0 0 calls failed (Server during this run) API Maker **4.8 vCPU** · Redis **0.2 vCPU** · MongoDB **1.2 vCPU** · whole server busy **85 %** · load generator busy **9 %** autocannon · Inserts told to 100 clients, as many as the server takes am_ws_load · what the clients received ## With every client connected The same runs once more, with 3,662,564 clients connected and waiting : what a server which is full of WebSocket clients still does. | | No client, or 10,000 | 3,662,564 clients connected | |---|--:|--:| | A notification for one person, 1,000 a second : delivery p50 | 0.94 ms | **1.28 ms** | | … p99 | 6.54 ms | **121 ms** | | A notification for one person, as many as the server takes | 21,208 / s | **8,384 / s** | | Get all with both tokens, 100 connections (autocannon) | 9,529 req/s | **3,997 req/s** | | … latency p50 / p99 | 10 ms / 21 ms | **14 ms / 289 ms** | **Notification, 1,000 a second** Calls / second (paced) 987 59,220 calls in 60 s, 10 connections Notifications / second 970 59,225 received by 3,662,564 clients Delivery p50 1.28ms average 4.51 ms Delivery p99 121ms max 454 ms Not delivered 0 0 calls failed (Server during this run) API Maker **3.5 vCPU** · Redis **0.9 vCPU** · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU** · whole server busy **60 %** · load generator busy **8 %** autocannon · A notification for one person, 1,000 a second, every client connected am_ws_load · what the clients received **Notification, as many as the server takes** Calls / second 8,481 508,854 calls in 60 s, 100 connections Notifications / second 8,384 508,954 received by 3,662,564 clients Delivery p50 5.85ms average 11.6 ms Delivery p99 194ms max 621 ms Not delivered 0 0 calls failed (Server during this run) API Maker **6.6 vCPU** · Redis **0.2 vCPU** · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU** · whole server busy **91 %** · load generator busy **17 %** autocannon · A notification for one person, as many as the server takes, every client connected am_ws_load · what the clients received **Get all with both tokens** Requests / second 3,997 239,825 requests in 60 s Latency p50 14ms average 24.52 ms Latency p99 289ms max 590 ms Errors 0 non-2xx, errors, timeouts (Server during this run) API Maker **5.3 vCPU** · Redis **0.0 vCPU** · MongoDB **1.4 vCPU** · sandboxes **0.0 vCPU** · whole server busy **94 %** · load generator busy **13 %** autocannon · get all with both tokens · 3,662,564 WebSocket clients connected ## Questions ### How many WebSocket connections can API Maker hold on 8 shared vCPUs and 32 GB ? 3,662,564 clients were connected at the same time on this server, each with both tokens and a subscription of its own, with MongoDB, Redis and two sandboxes on the same machine. Memory is what ends first : a client costs about 8.8 KB of the server in all. ### How much memory does a WebSocket client cost ? About 8.8 KB : 3.2 KB in the API Maker process, 4.5 KB in the Linux kernel (its socket) and 1.1 KB in Redis (its subscription). Measured between 1,000,000 and 3,000,000 clients which wait, each connected with both tokens and one subscription. ### How many clients can connect each second ? 10,939 clients a second connected with both tokens, subscribed and left, 100 at a time ; 24,719 a second without a subscription. With a can user connect code on the event : 9,280 a second. ### How fast does a notification reach a client ? At 1,000 notifications a second, each for one person among 10,000 : 0.94 ms from the HTTP call to the client (p50), 6.54 ms for 99 % of them. With as many calls as the server takes : 21,208 notifications a second. ### Do connected WebSocket clients slow the APIs down ? Get all with both tokens answered 9,529 requests a second with no WebSocket client, and 3,997 with 3,662,564 clients connected and waiting. A client which waits costs memory ; its CPU is a ping a minute. --- # API Maker WebSocket benchmark : 2 vCPU, 4 GB RAM (Linode dedicated CPU) > API Maker WebSockets on 2 dedicated vCPUs, 4 GB (Linode) : 338,006 clients connected at once, 8 KB each, 3,464 new clients a second, with memory and outputs. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html WebSocket benchmark · Linode (Akamai Cloud) · Dedicated CPU · 14 October 2026 **2 vCPU, 4 GB RAM : 338,006 WebSocket clients connected at once.** API Maker 4.0.0 on a Linode Dedicated 4 GB (g6-dedicated-2) : 2 dedicated vCPUs and 4 GB of RAM at $36 a month, its MongoDB and Redis on the same machine. A second server opened WebSocket clients, each with both tokens and a subscription of its own, until the memory of the server was full, while autocannon made the calls which notify them : every run 60 seconds, the memory and CPU of every part sampled each second. Clients connected 338,006 the memory was full : 451 MB left Memory per client 8.5KB API Maker 3.1 · kernel 4.3 · Redis 1.0 New clients / second 3,464 both tokens and a subscription · 7,077 without one Notification delivered in 1.74ms p50 at 1,000 a second · p99 3.70 ms ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Dedicated 4 GB (g6-dedicated-2), dedicated cpu, $36 / month | | CPU | AMD EPYC 7642 48-Core Processor, 2 dedicated vCPUs (KVM)
KVM guest, 1 thread per core · L1d 128 KiB (2 instances) · L2 1 MiB (2 instances) · L3 32 MiB (2 instances) · BogoMIPS 4600.00 | | Memory | 4 GB (3,915 MB usable), swap 4.3 GB (496 MB of Linode + 3.8 GB made by the installer) | | Disk, region | 80 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer : one worker thread per vCPU, up to 1,048,576 open files for the service (`LimitNOFILE`), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Network limits | as the installer sets them : 1,002,240 connections tracked by the firewall of Linux (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted (`net.core.somaxconn`). The memory of all its TCP connections together : raised by API Maker as the clients came, to 979 MB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) : on the same server. No other database runs | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 404 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default) | | Load generator | Dedicated 8 GB (g6-dedicated-4) : AMD EPYC 7642 48-Core Processor, 4 dedicated vCPUs, Ubuntu 24.04.4 LTS. The WebSocket clients : am_ws_load, a program in Rust made for these benchmarks, a socket and a task per client, from 21 addresses of the load generator. The HTTP calls : Node.js 24.21.0, autocannon 8.0.0 | | Network | A VLAN of the same data centre, round trip 0.42 ms (ping) | | Date | 14 October 2026, 03:18 to 03:57 UTC | Only what the run needs was running : API Maker and its two sandboxes, its MongoDB and its Redis. API Maker was restarted and the swap emptied before the run. How every number was taken : [How the WebSocket benchmarks are made](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html). The APIs of this server : [2 vCPU · 4 GB, API benchmark](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-2-vcpu-4gb.html). ## The data - **The clients** connect to `ws://:38246/?x-am-authorization=&x-am-user-authorization=` : the token of an API user, and the token of a person, a row of the `customers` table of the [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`) made by a DB token generator. API Maker checks both. - **A subscription** is one `REGISTER` for the custom WebSocket event `order-updates` with a condition of its own : `{ conditionType: 'RESPONSE', criteria: { recipientId: '' } }`. It is the way [one notification reaches one person](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html). - **A notification** for one person is 141 bytes ; a row of the dataset told to the clients of a table is 321 bytes. - **The tables** are the ones of the [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html#the-data), in MongoDB : ten rows of customers, ten columns each. ## Results at a glance **New clients per second** [Connect : the token of the API user](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#connect-1-token) · 7,417 [Connect : both tokens](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#connect-2-tokens) · 7,077 [Connect with both tokens and subscribe](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#subscribe) · 3,464 [Subscribe to an event with a can user connect code](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#can-user-connect) · the code ran in the server · 2,891 [Subscribe : the code reads the database](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#can-user-connect-database) · the code ran in the sandbox · 1,368 [Subscribe : the code reads the clock](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#can-user-connect-sandbox) · the code ran in the sandbox · 2,550 100 clients at a time connect, are let in and leave, for 60 seconds. **Notifications per second** [A notification for one person](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#one-person) · 6,757 calls / second · 6,618 [A broadcast](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#broadcast) · 71 calls / second · 69,874 [Rows inserted in a table](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html#insert) · 506 calls / second · 49,312 As many calls as the server takes : what the clients received each second. ## How many clients fit Clients connect 2,000 a second, level after level, each with both tokens and a subscription of its own ; at each level they wait 30 seconds while the server is sampled (the level the run stops at, 60). The run stopped adding clients at **338,006** : the memory of the server was full. 430 MB of its 3,916 MB were still counted as available, and Linux had moved 240 MB to the swap since the clients began to connect, to make that room : 190 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server). > Diagram : Clients connected and memory used during the run > > The run of this server, second after second : the WebSocket clients connected, up to 338,006, and the memory the server used, up to 3,496 MB of 3,915 MB. API Maker · MongoDB of API Maker · Redis · Sandboxes · Linux : its sockets, Docker, the rest · Available No client at rest 10,000 clients connected 25,000 clients connected 50,000 clients connected 100,000 clients connected 150,000 clients connected 200,000 clients connected 250,000 clients connected 300,000 clients connected 338,006 clients connected | Clients | API Maker | Redis | Kernel | MongoDB | Sandboxes | Server, used | Available | Swap | CPU busy | |---|--:|--:|--:|--:|--:|--:|--:|--:|--:| | None (at rest) | 109 | 1 | 202 | 123 | 51 | **767** | 3,149 | 0 | 1.7 % | | **10,000** | 148 | 12 | 271 | 155 | 220 | **1,100** | 2,816 | 0 | 1.7 % | | **25,000** | 200 | 27 | 311 | 190 | 220 | **1,239** | 2,677 | 0 | 1.5 % | | **50,000** | 278 | 52 | 414 | 186 | 220 | **1,429** | 2,488 | 0 | 2.9 % | | **100,000** | 438 | 102 | 627 | 186 | 219 | **1,852** | 2,064 | 0 | 3.1 % | | **150,000** | 603 | 157 | 838 | 187 | 219 | **2,238** | 1,678 | 0 | 5.1 % | | **200,000** | 753 | 204 | 1,050 | 187 | 219 | **2,600** | 1,316 | 0 | 8.3 % | | **250,000** | 892 | 250 | 1,264 | 186 | 219 | **3,010** | 906 | 0 | 10.9 % | | **300,000** | 1,008 | 313 | 1,469 | 157 | 159 | **3,331** | 585 | 136 | 13.6 % | | **338,006** | 1,108 | 347 | 1,627 | 125 | 99 | **3,465** | 451 | 270 | 13.8 % | Memory in MB. API Maker is the resident memory of its process ; Redis is the memory of its data (`used_memory`) ; the kernel of Linux keeps every socket and every tracked connection in its slab ; a container is counted the way `docker stats` counts it. CPU busy is the whole server while the clients wait : the server pings every client once a minute, and each answers. ### Memory when the server is full With **338,006 clients** connected and waiting, of the 3,916 MB of the server : | Part | At rest, no client | 338,006 clients | More | |---|--:|--:|--:| | **API Maker** (process) | 109 MB | **1,108 MB** | + 1,000 MB | | Redis (container) | 3 MB | **356 MB** | + 353 MB | | Linux kernel : sockets, tracked connections (slab) | 202 MB | **1,627 MB** | + 1,424 MB | | MongoDB of API Maker (container) | 123 MB | **125 MB** | + 1 MB | | Sandboxes (2 containers) | 51 MB | **99 MB** | + 48 MB | | **Whole server**, used | 767 MB | **3,465 MB** | + 2,699 MB | | Available | 3,149 MB | **451 MB** | | | Swap used | 0 MB | **270 MB** | | | Open files of API Maker | 27 | **338,034** | | | Keys of Redis · channels it listens on | 13 · 5 | **676,028 · 338,011** | | MongoDB and the sandboxes grew during the runs before this one (the inserts, the code of the events), not with the clients. ### What a client costs Between 100,000 and 250,000 clients (4 levels), each client more cost the server **8.5 KB** : | Where | Per client | What it is | |---|--:|---| | **API Maker** | **3.1 KB** | The client itself : its socket and the one task which reads it, its tokens and what they said, its subscription and the channel it is told on. | | Linux kernel | 4.3 KB | The TCP socket, and the entry of the connection in the table of the firewall (Docker makes Linux track every connection). | | Redis | 1.0 KB | The subscription : its key, its place in the list of its condition, and the channel API Maker listens on. | | **In all** | **8.5 KB** | 123,507 clients per GB of memory. | Measured over the levels at which nothing was in the swap. The memory the whole server had available went down by 7.9 KB per client : MongoDB, the sandboxes and the cache of files give some back while the clients take theirs. ## One more subscription, and a broadcast to everybody With 50,000 clients connected, every client sent a second `REGISTER`, for an event without a condition (`announcements`), 2,000 of them a second : 50,000 were taken in 25.0 s. They waited 30 seconds with two subscriptions each, were told 3 broadcasts, one call of the emit event WS API each, and took the subscription back with `UNREGISTER`. One subscription more 1.2KB per client : API Maker 0.5 KB · Redis 0.8 KB A broadcast to 50k clients 0.91s until the last client read it Half of them told after 493ms the first after 172 ms Clients told / second 54,802 one call, every client | Broadcast | Clients told | The call answered after | The first client | Half of them | 99 % of them | The last one | Clients told a second | |---|--:|--:|--:|--:|--:|--:|--:| | 1 | 50,000 of 50,000 | 0.93 s | 179 ms | 534 ms | 904 ms | **916 ms** | 54,587 | | 2 | 50,000 of 50,000 | 0.92 s | 172 ms | 493 ms | 898 ms | **912 ms** | 54,802 | | 3 | 50,000 of 50,000 | 1.02 s | 168 ms | 579 ms | 998 ms | **1,013 ms** | 49,346 | One call of the emit event WS API tells every client : API Maker asks Redis for the clients of the event, publishes the notification for each of them, and the server which holds a client sends it. The times are counted from the moment the call is written to the moment a client reads its notification. | Memory, 50,000 clients | One subscription each | Two subscriptions each | A subscription more, per client | |---|--:|--:|--:| | API Maker | 278 MB | 300 MB | 0.5 KB | | Redis (its data) | 52 MB | 88 MB | 0.8 KB | | Keys of Redis · channels | 100,016 · 50,005 | 150,017 · 100,005 | | | **Whole server**, less available | | | **1.2 KB** | ## New clients per second How many clients a second the server lets in : 100 clients at a time connect, are let in and leave, one after the other, for 60 seconds (after 5 seconds which are not counted). It is what a server faces when its clients all come back, after a deployment or a network cut. The times are counted from the start of the TCP connection. ### Connect : the token of the API user A client connects with `x-am-authorization` alone, is told `CONNECTED`, and leaves. API Maker checks the token of the API user and finds its groups : what every WebSocket client costs before it asks for anything. Clients / second 7,417 445,467 clients in 60 s, 100 at a time Let in after, p50 7.34ms connected 7.34 ms · TCP 0.25 ms Let in after, p99 13.6ms max 26.4 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.9 vCPU** · MongoDB **0.0 vCPU** · whole server busy **99 %** · load generator busy **60 %** am_ws_load · Connect : the token of the API user · 60 s ### Connect : both tokens A client connects with `x-am-authorization` and `x-am-user-authorization`, is told `CONNECTED`, and leaves. Both tokens are checked : the one of the API user, and the one of a person, made by the DB token generator of the account. Clients / second 7,077 425,048 clients in 60 s, 100 at a time Let in after, p50 7.76ms connected 7.76 ms · TCP 0.25 ms Let in after, p99 14.5ms max 31.6 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.9 vCPU** · MongoDB **0.0 vCPU** · whole server busy **100 %** · load generator busy **58 %** am_ws_load · Connect : both tokens · 60 s ### Connect with both tokens and subscribe The whole of what an application does : connect with both tokens, `CONNECTED`, one `REGISTER` for a custom WebSocket event with a condition of its own (`recipientId` : its user id), the answer, then leave. API Maker checks the groups and the auth provider of the event, keeps the subscription in Redis and listens on its channel ; when the client leaves, all of it is taken back. Clients / second 3,464 208,028 clients in 60 s, 100 at a time Let in after, p50 25.1ms connected 5.65 ms · TCP 0.23 ms Let in after, p99 35.0ms max 46.3 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.5 vCPU** · Redis **0.2 vCPU** · whole server busy **100 %** · load generator busy **36 %** am_ws_load · Connect with both tokens and subscribe · 60 s ### Subscribe to an event with a can user connect code The same, on an event whose *can user connect code* decides who may subscribe : it reads the person of `x-am-user-authorization` from `g.req.auth`. The code ran in the server itself (lean code, QuickJS). Clients / second 2,891 173,650 clients in 60 s, 100 at a time Let in after, p50 30.1ms connected 6.26 ms · TCP 0.24 ms Let in after, p99 43.1ms max 90.8 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.5 vCPU** · Redis **0.2 vCPU** · whole server busy **100 %** · load generator busy **32 %** am_ws_load · Subscribe to an event with a can user connect code · 60 s ### Subscribe : the code reads the database The same, with a can user connect code which also reads the person from the database (`g.sys.db.getAll` with a `find`) before it answers : one read of MongoDB for every subscription. The code ran in a sandbox of the account. Clients / second 1,368 82,156 clients in 60 s, 100 at a time Let in after, p50 66.6ms connected 9.68 ms · TCP 0.25 ms Let in after, p99 93.1ms max 114 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **0.7 vCPU** · Redis **0.1 vCPU** · MongoDB **0.3 vCPU** · sandboxes **0.7 vCPU** · whole server busy **100 %** · load generator busy **16 %** am_ws_load · Subscribe : the code reads the database · 60 s ### Subscribe : the code reads the clock The same, with a can user connect code which reads the time of the machine (`Date.now()`) : code which is not lean, so API Maker runs it in a sandbox of the account. The code ran in a sandbox of the account. Clients / second 2,550 153,134 clients in 60 s, 100 at a time Let in after, p50 35.3ms connected 6.06 ms · TCP 0.24 ms Let in after, p99 48.8ms max 76.8 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.3 vCPU** · Redis **0.2 vCPU** · sandboxes **0.3 vCPU** · whole server busy **100 %** · load generator busy **30 %** am_ws_load · Subscribe : the code reads the clock · 60 s ## Can user connect code An event of the WebSocket Events page can carry a *can user connect code* : API Maker runs it for every subscription to the event, with the tokens of the client in `g.req.auth` and the subscription in `g.req.eventData`, and lets the client subscribe when it returns `{ canConnect: true }`. Three codes were measured : one which reads the person of the token, one which also reads the database, one which reads the clock. **Reads the person of the token** **Can user connect code of the event checked-token : ran in the server** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { // The person of x-am-user-authorization : only somebody who signed in subscribes, from a country we serve. const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; return { canConnect: person.country === 'India', errorText: 'Not available in your country.' }; }; module.exports = main; ``` **Reads the database** **Can user connect code of the event checked-database : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // Still a customer ? One read of the database for every subscription. const rows = await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers', queryParams: { find: { customer_id: person.customer_id } } }); return { canConnect: rows.length === 1 && rows[0].country === 'India', errorText: 'Not a customer any more.' }; }; module.exports = main; ``` **Reads the clock** **Can user connect code of the event checked-sandbox : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // The time of the machine : this code runs in the sandbox of the account. const hour = new Date(Date.now()).getUTCHours(); return { canConnect: person.country === 'India' && hour >= 0, errorText: 'Not available in your country.' }; }; module.exports = main; ``` | Can user connect code | Runs in | Clients / second | Subscribed after, p50 | p99 | Against no code | |---|---|--:|--:|--:|--:| | No code | – | **3,464** | 25.1 ms | 35.0 ms | – | | Reads the person of the token | the server (QuickJS) | **2,891** | 30.1 ms | 43.1 ms | 17 % fewer | | Reads the person from the database | a sandbox of the account | **1,368** | 66.6 ms | 93.1 ms | 61 % fewer | | Reads the clock | a sandbox of the account | **2,550** | 35.3 ms | 48.8 ms | 26 % fewer | Lean code (it only reads what it is handed) runs in the server itself, with QuickJS, on the thread which serves the client. Code which needs more runs in a sandbox of the account : every subscription is then a round trip to the sandbox. ## Notifications With 10,000 clients connected, autocannon makes the HTTP calls which notify them, for 60 seconds, and the clients count what they receive and how late. Each kind of notification is measured twice : at a pace far under what the server takes, which shows how long a notification takes, and with no pace, which shows how many a second the server tells. *Delivery* is the time from the moment autocannon writes the request to the moment the client reads the notification : the HTTP call, API Maker, Redis, and the WebSocket. ### A notification for one person autocannon calls the [emit event WS API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-emit-event-ws-api.html) with both tokens ; every call names another one of the 10,000 connected clients (`recipientId`), which is the only one told. The clients measure how long each notification took from the moment its request was written. **1,000 calls a second** Calls / second (paced) 1,000 60,006 calls in 60 s, 10 connections Notifications / second 983 60,016 received by 10,000 clients Delivery p50 1.74ms average 1.79 ms Delivery p99 3.70ms max 7.91 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.3 vCPU** · Redis **0.0 vCPU** · whole server busy **19 %** · load generator busy **11 %** autocannon · A notification for one person, 1,000 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 6,757 405,367 calls in 60 s, 100 connections Notifications / second 6,618 405,464 received by 10,000 clients Delivery p50 14.7ms average 14.6 ms Delivery p99 21.5ms max 39.4 ms Not delivered 0 0 calls failed (Server during this run) API Maker **1.6 vCPU** · Redis **0.1 vCPU** · whole server busy **99 %** · load generator busy **39 %** autocannon · A notification for one person, as many as the server takes am_ws_load · what the clients received ### A broadcast 1,000 more clients subscribe to an event without a condition : every call of the emit event WS API reaches all 1,000 of them. **5 calls a second** Calls / second (paced) 5 300 calls in 60 s, 1 connection Notifications / second 4,930 301,000 received by 1,000 clients Delivery p50 10.3ms average 10.5 ms Delivery p99 18.3ms max 23.3 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.2 vCPU** · whole server busy **9 %** · load generator busy **8 %** autocannon · A broadcast to 1,000 clients, 5 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 71 4,266 calls in 60 s, 10 connections Notifications / second 69,874 4,275,000 received by 1,000 clients Delivery p50 126ms average 124 ms Delivery p99 207ms max 270 ms Not delivered 0 0 calls failed (Server during this run) API Maker **1.8 vCPU** · Redis **0.1 vCPU** · whole server busy **98 %** · load generator busy **54 %** autocannon · A broadcast to 1,000 clients, as many as the server takes am_ws_load · what the clients received ### Rows inserted in a table 100 clients subscribe to the insert API of a table (`SCHEMA_POST_BULK_INSERT` on `inserts_public`, `getEventData: true`) ; autocannon inserts rows of the [dataset](https://apimaker.dev/json/benchmark_dataset.json) through the [insert API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html), and every row saved is told to each of the 100 clients, with its columns. **50 calls a second** Calls / second (paced) 50 3,000 calls in 60 s, 10 connections Notifications / second 4,970 301,000 received by 100 clients Delivery p50 35.1ms average 34.3 ms Delivery p99 54.8ms max 63.4 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · MongoDB **0.0 vCPU** · whole server busy **13 %** · load generator busy **11 %** autocannon · Inserts told to 100 clients, 50 inserts a second am_ws_load · what the clients received **As many as the server takes** Calls / second 506 30,386 calls in 60 s, 100 connections Notifications / second 49,312 3,046,100 received by 100 clients Delivery p50 693ms average 674 ms Delivery p99 845ms max 999 ms Not delivered 0 0 calls failed (Server during this run) API Maker **1.4 vCPU** · Redis **0.1 vCPU** · MongoDB **0.3 vCPU** · whole server busy **98 %** · load generator busy **39 %** autocannon · Inserts told to 100 clients, as many as the server takes am_ws_load · what the clients received ## With every client connected The same runs once more, with 338,006 clients connected and waiting : what a server which is full of WebSocket clients still does. | | No client, or 10,000 | 338,006 clients connected | |---|--:|--:| | A notification for one person, 1,000 a second : delivery p50 | 1.74 ms | **1.76 ms** | | … p99 | 3.70 ms | **3.03 ms** | | A notification for one person, as many as the server takes | 6,618 / s | **5,705 / s** | | Get all with both tokens, 100 connections (autocannon) | 3,058 req/s | **2,614 req/s** | | … latency p50 / p99 | 32 ms / 55 ms | **33 ms / 170 ms** | **Notification, 1,000 a second** Calls / second (paced) 1,000 60,005 calls in 60 s, 10 connections Notifications / second 983 60,015 received by 338,006 clients Delivery p50 1.76ms average 1.79 ms Delivery p99 3.03ms max 41.1 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.4 vCPU** · Redis **0.0 vCPU** · whole server busy **28 %** · load generator busy **19 %** autocannon · A notification for one person, 1,000 a second, every client connected am_ws_load · what the clients received **Notification, as many as the server takes** Calls / second 5,791 347,446 calls in 60 s, 100 connections Notifications / second 5,705 347,546 received by 338,006 clients Delivery p50 15.1ms average 17.1 ms Delivery p99 64.8ms max 263 ms Not delivered 0 0 calls failed (Server during this run) API Maker **1.6 vCPU** · Redis **0.1 vCPU** · whole server busy **100 %** · load generator busy **45 %** autocannon · A notification for one person, as many as the server takes, every client connected am_ws_load · what the clients received **Get all with both tokens** Requests / second 2,614 156,776 requests in 60 s Latency p50 33ms average 37.77 ms Latency p99 170ms max 413 ms Errors 0 non-2xx, errors, timeouts (Server during this run) API Maker **1.1 vCPU** · Redis **0.0 vCPU** · MongoDB **0.6 vCPU** · whole server busy **100 %** · load generator busy **34 %** autocannon · get all with both tokens · 338,006 WebSocket clients connected ## A restart API Maker was restarted (`systemctl restart api_maker_be`) with 253,504 clients connected : the newest left first, down to 75 % of the 338,006 it held. Every client of a restarted server comes back within the same seconds and waits for its turn with its request in the kernel, about 4 KB each : a server needs that room. It takes what Redis keeps of them out first, then closes every client with the code `1001` (*Server is going away*) ; each client waits one to five seconds, as an application does, connects again with the same tokens and sends its `REGISTER` again. The server which comes back lets 256 clients in at a time and handles the messages of 256 at a time, the others wait for their turn : its memory comes back to what it was, not higher. Clients dropped 253,504 of 253,504 connected All back after 159.1s the restart itself : 29.6 s A client was away, p50 68.7s its own wait of 1 to 5 s counted A client was away, p99 96.5s the longest : 154 s After the restart, with the 253,504 clients back : API Maker 945 MB (1,108 MB before it), 1,125 MB of memory available. They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,000 arrived**, in 1.75 ms (p50) and 2.94 ms (p99). A client whose subscription had not come back with it would have been told nothing. ### Every client leaves at once At the end of the run, the 253,504 clients closed their connection in the same second, as when a network or a load balancer in front of the server goes. The server had closed every one of their sockets after **15.1 s**, and Redis held nothing of them any more after **16.1 s**. A socket is closed at once, and Redis is told behind it. ## Questions ### How many WebSocket connections can API Maker hold on 2 dedicated vCPUs and 4 GB ? 338,006 clients were connected at the same time on this server, each with both tokens and a subscription of its own, with MongoDB, Redis and two sandboxes on the same machine. Memory is what ends first : a client costs about 8.5 KB of the server in all. ### How much memory does a WebSocket client cost ? About 8.5 KB : 3.1 KB in the API Maker process, 4.3 KB in the Linux kernel (its socket) and 1.0 KB in Redis (its subscription). Measured between 100,000 and 250,000 clients which wait, each connected with both tokens and one subscription. ### How many clients can connect each second ? 3,464 clients a second connected with both tokens, subscribed and left, 100 at a time ; 7,077 a second without a subscription. With a can user connect code on the event : 2,891 a second. ### How fast does a notification reach a client ? At 1,000 notifications a second, each for one person among 10,000 : 1.74 ms from the HTTP call to the client (p50), 3.70 ms for 99 % of them. With as many calls as the server takes : 6,618 notifications a second. ### Do connected WebSocket clients slow the APIs down ? Get all with both tokens answered 3,058 requests a second with no WebSocket client, and 2,614 with 338,006 clients connected and waiting. A client which waits costs memory ; its CPU is a ping a minute. --- # API Maker WebSocket benchmark : 4 vCPU, 8 GB RAM (Linode dedicated CPU) > API Maker WebSockets on 4 dedicated vCPUs, 8 GB (Linode) : 795,888 clients connected at once, 9 KB each, 6,627 new clients a second, with memory and outputs. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html WebSocket benchmark · Linode (Akamai Cloud) · Dedicated CPU · 14 October 2026 **4 vCPU, 8 GB RAM : 795,888 WebSocket clients connected at once.** API Maker 4.0.0 on a Linode Dedicated 8 GB (g6-dedicated-4) : 4 dedicated vCPUs and 8 GB of RAM at $72 a month, its MongoDB and Redis on the same machine. A second server opened WebSocket clients, each with both tokens and a subscription of its own, until the memory of the server was full, while autocannon made the calls which notify them : every run 60 seconds, the memory and CPU of every part sampled each second. Clients connected 795,888 the memory was full : 1,024 MB left Memory per client 8.7KB API Maker 3.3 · kernel 4.4 · Redis 1.1 New clients / second 6,627 both tokens and a subscription · 12,535 without one Notification delivered in 1.04ms p50 at 1,000 a second · p99 2.03 ms ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Dedicated 8 GB (g6-dedicated-4), dedicated cpu, $72 / month | | CPU | AMD EPYC 7642 48-Core Processor, 4 dedicated vCPUs (KVM)
KVM guest, 1 thread per core · L1d 256 KiB (4 instances) · L2 2 MiB (4 instances) · L3 64 MiB (4 instances) · BogoMIPS 4599.99 | | Memory | 8 GB (7,941 MB usable), swap 8.3 GB (496 MB of Linode + 7.8 GB made by the installer) | | Disk, region | 160 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer : one worker thread per vCPU, up to 2,032,896 open files for the service (`LimitNOFILE`), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Network limits | as the installer sets them : 2,032,896 connections tracked by the firewall of Linux (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted (`net.core.somaxconn`). The memory of all its TCP connections together : raised by API Maker as the clients came, to 1.9 GB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) : on the same server. No other database runs | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 404 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default) | | Load generator | Dedicated 16 GB (g6-dedicated-8) : AMD EPYC 7642 48-Core Processor, 8 dedicated vCPUs, Ubuntu 24.04.4 LTS. The WebSocket clients : am_ws_load, a program in Rust made for these benchmarks, a socket and a task per client, from 41 addresses of the load generator. The HTTP calls : Node.js 24.21.0, autocannon 8.0.0 | | Network | A VLAN of the same data centre, round trip 0.38 ms (ping) | | Date | 14 October 2026, 03:18 to 03:58 UTC | Only what the run needs was running : API Maker and its two sandboxes, its MongoDB and its Redis. API Maker was restarted and the swap emptied before the run. How every number was taken : [How the WebSocket benchmarks are made](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html). The APIs of this server : [4 vCPU · 8 GB, API benchmark](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-4-vcpu-8gb.html). ## The data - **The clients** connect to `ws://:38246/?x-am-authorization=&x-am-user-authorization=` : the token of an API user, and the token of a person, a row of the `customers` table of the [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`) made by a DB token generator. API Maker checks both. - **A subscription** is one `REGISTER` for the custom WebSocket event `order-updates` with a condition of its own : `{ conditionType: 'RESPONSE', criteria: { recipientId: '' } }`. It is the way [one notification reaches one person](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html). - **A notification** for one person is 141 bytes ; a row of the dataset told to the clients of a table is 321 bytes. - **The tables** are the ones of the [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html#the-data), in MongoDB : ten rows of customers, ten columns each. ## Results at a glance **New clients per second** [Connect : the token of the API user](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#connect-1-token) · 13,849 [Connect : both tokens](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#connect-2-tokens) · 12,535 [Connect with both tokens and subscribe](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#subscribe) · 6,627 [Subscribe to an event with a can user connect code](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#can-user-connect) · the code ran in the server · 5,533 [Subscribe : the code reads the database](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#can-user-connect-database) · the code ran in the sandbox · 2,046 [Subscribe : the code reads the clock](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#can-user-connect-sandbox) · the code ran in the sandbox · 4,505 100 clients at a time connect, are let in and leave, for 60 seconds. **Notifications per second** [A notification for one person](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#one-person) · 13,049 calls / second · 12,791 [A broadcast](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#broadcast) · 120 calls / second · 117,698 [Rows inserted in a table](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html#insert) · 779 calls / second · 76,505 As many calls as the server takes : what the clients received each second. ## How many clients fit Clients connect 4,000 a second, level after level, each with both tokens and a subscription of its own ; at each level they wait 30 seconds while the server is sampled (the level the run stops at, 60). The run stopped adding clients at **795,888** : the memory of the server was full. 922 MB of its 7,941 MB were still counted as available, and Linux had moved 537 MB to the swap since the clients began to connect, to make that room : 385 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server). > Diagram : Clients connected and memory used during the run > > The run of this server, second after second : the WebSocket clients connected, up to 795,888, and the memory the server used, up to 7,040 MB of 7,941 MB. API Maker · MongoDB of API Maker · Redis · Sandboxes · Linux : its sockets, Docker, the rest · Available No client at rest 10,000 clients connected 50,000 clients connected 100,000 clients connected 200,000 clients connected 300,000 clients connected 400,000 clients connected 500,000 clients connected 600,000 clients connected 700,000 clients connected 795,888 clients connected | Clients | API Maker | Redis | Kernel | MongoDB | Sandboxes | Server, used | Available | Swap | CPU busy | |---|--:|--:|--:|--:|--:|--:|--:|--:|--:| | None (at rest) | 118 | 1 | 224 | 123 | 55 | **852** | 7,090 | 0 | 0.8 % | | **10,000** | 156 | 12 | 322 | 158 | 480 | **1,457** | 6,485 | 0 | 1.6 % | | **50,000** | 286 | 52 | 457 | 206 | 479 | **1,775** | 6,166 | 0 | 1.4 % | | **100,000** | 440 | 103 | 681 | 203 | 479 | **2,164** | 5,777 | 0 | 2.8 % | | **200,000** | 766 | 203 | 1,129 | 203 | 479 | **3,001** | 4,940 | 0 | 4.1 % | | **300,000** | 1,086 | 313 | 1,579 | 203 | 479 | **3,798** | 4,143 | 0 | 5.7 % | | **400,000** | 1,389 | 406 | 2,007 | 203 | 479 | **4,499** | 3,442 | 0 | 10.1 % | | **500,000** | 1,732 | 498 | 2,430 | 203 | 479 | **5,299** | 2,643 | 0 | 13.0 % | | **600,000** | 2,031 | 625 | 2,848 | 203 | 479 | **6,135** | 1,806 | 0 | 16.6 % | | **700,000** | 2,300 | 716 | 3,276 | 183 | 386 | **6,758** | 1,184 | 124 | 18.8 % | | **795,888** | 2,474 | 806 | 3,691 | 66 | 203 | **6,917** | 1,024 | 594 | 19.3 % | Memory in MB. API Maker is the resident memory of its process ; Redis is the memory of its data (`used_memory`) ; the kernel of Linux keeps every socket and every tracked connection in its slab ; a container is counted the way `docker stats` counts it. CPU busy is the whole server while the clients wait : the server pings every client once a minute, and each answers. ### Memory when the server is full With **795,888 clients** connected and waiting, of the 7,941 MB of the server : | Part | At rest, no client | 795,888 clients | More | |---|--:|--:|--:| | **API Maker** (process) | 118 MB | **2,474 MB** | + 2,356 MB | | Redis (container) | 3 MB | **802 MB** | + 799 MB | | Linux kernel : sockets, tracked connections (slab) | 224 MB | **3,691 MB** | + 3,467 MB | | MongoDB of API Maker (container) | 123 MB | **66 MB** | − 57 MB | | Sandboxes (2 containers) | 55 MB | **203 MB** | + 148 MB | | **Whole server**, used | 852 MB | **6,917 MB** | + 6,066 MB | | Available | 7,090 MB | **1,024 MB** | | | Swap used | 0 MB | **594 MB** | | | Open files of API Maker | 28 | **795,920** | | | Keys of Redis · channels it listens on | 13 · 5 | **1,591,792 · 795,893** | | MongoDB and the sandboxes grew during the runs before this one (the inserts, the code of the events), not with the clients. ### What a client costs Between 200,000 and 600,000 clients (5 levels), each client more cost the server **8.7 KB** : | Where | Per client | What it is | |---|--:|---| | **API Maker** | **3.3 KB** | The client itself : its socket and the one task which reads it, its tokens and what they said, its subscription and the channel it is told on. | | Linux kernel | 4.4 KB | The TCP socket, and the entry of the connection in the table of the firewall (Docker makes Linux track every connection). | | Redis | 1.1 KB | The subscription : its key, its place in the list of its condition, and the channel API Maker listens on. | | **In all** | **8.7 KB** | 120,250 clients per GB of memory. | Measured over the levels at which nothing was in the swap. The memory the whole server had available went down by 8.0 KB per client : MongoDB, the sandboxes and the cache of files give some back while the clients take theirs. ## One more subscription, and a broadcast to everybody With 100,000 clients connected, every client sent a second `REGISTER`, for an event without a condition (`announcements`), 4,000 of them a second : 100,000 were taken in 25.0 s. They waited 30 seconds with two subscriptions each, were told 3 broadcasts, one call of the emit event WS API each, and took the subscription back with `UNREGISTER`. One subscription more 1.2KB per client : API Maker 0.5 KB · Redis 0.8 KB A broadcast to 100k clients 1.39s until the last client read it Half of them told after 889ms the first after 376 ms Clients told / second 72,124 one call, every client | Broadcast | Clients told | The call answered after | The first client | Half of them | 99 % of them | The last one | Clients told a second | |---|--:|--:|--:|--:|--:|--:|--:| | 1 | 100,000 of 100,000 | 1.45 s | 453 ms | 942 ms | 1,435 ms | **1,447 ms** | 69,113 | | 2 | 100,000 of 100,000 | 1.39 s | 376 ms | 889 ms | 1,373 ms | **1,387 ms** | 72,124 | | 3 | 100,000 of 100,000 | 1.40 s | 365 ms | 861 ms | 1,390 ms | **1,402 ms** | 71,334 | One call of the emit event WS API tells every client : API Maker asks Redis for the clients of the event, publishes the notification for each of them, and the server which holds a client sends it. The times are counted from the moment the call is written to the moment a client reads its notification. | Memory, 100,000 clients | One subscription each | Two subscriptions each | A subscription more, per client | |---|--:|--:|--:| | API Maker | 440 MB | 484 MB | 0.5 KB | | Redis (its data) | 103 MB | 175 MB | 0.8 KB | | Keys of Redis · channels | 200,016 · 100,005 | 300,017 · 200,005 | | | **Whole server**, less available | | | **1.2 KB** | ## New clients per second How many clients a second the server lets in : 100 clients at a time connect, are let in and leave, one after the other, for 60 seconds (after 5 seconds which are not counted). It is what a server faces when its clients all come back, after a deployment or a network cut. The times are counted from the start of the TCP connection. ### Connect : the token of the API user A client connects with `x-am-authorization` alone, is told `CONNECTED`, and leaves. API Maker checks the token of the API user and finds its groups : what every WebSocket client costs before it asks for anything. Clients / second 13,849 831,768 clients in 60 s, 100 at a time Let in after, p50 4.28ms connected 4.28 ms · TCP 0.28 ms Let in after, p99 8.27ms max 30.5 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **3.8 vCPU** · MongoDB **0.0 vCPU** · whole server busy **97 %** · load generator busy **59 %** am_ws_load · Connect : the token of the API user · 60 s ### Connect : both tokens A client connects with `x-am-authorization` and `x-am-user-authorization`, is told `CONNECTED`, and leaves. Both tokens are checked : the one of the API user, and the one of a person, made by the DB token generator of the account. Clients / second 12,535 752,875 clients in 60 s, 100 at a time Let in after, p50 4.73ms connected 4.73 ms · TCP 0.28 ms Let in after, p99 9.16ms max 26.4 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **3.8 vCPU** · MongoDB **0.0 vCPU** · whole server busy **98 %** · load generator busy **54 %** am_ws_load · Connect : both tokens · 60 s ### Connect with both tokens and subscribe The whole of what an application does : connect with both tokens, `CONNECTED`, one `REGISTER` for a custom WebSocket event with a condition of its own (`recipientId` : its user id), the answer, then leave. API Maker checks the groups and the auth provider of the event, keeps the subscription in Redis and listens on its channel ; when the client leaves, all of it is taken back. Clients / second 6,627 397,988 clients in 60 s, 100 at a time Let in after, p50 13.4ms connected 3.13 ms · TCP 0.25 ms Let in after, p99 19.3ms max 27.6 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **3.0 vCPU** · Redis **0.4 vCPU** · MongoDB **0.0 vCPU** · whole server busy **96 %** · load generator busy **34 %** am_ws_load · Connect with both tokens and subscribe · 60 s ### Subscribe to an event with a can user connect code The same, on an event whose *can user connect code* decides who may subscribe : it reads the person of `x-am-user-authorization` from `g.req.auth`. The code ran in the server itself (lean code, QuickJS). Clients / second 5,533 332,290 clients in 60 s, 100 at a time Let in after, p50 16.0ms connected 3.53 ms · TCP 0.24 ms Let in after, p99 23.1ms max 37.8 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **3.1 vCPU** · Redis **0.3 vCPU** · MongoDB **0.0 vCPU** · whole server busy **98 %** · load generator busy **30 %** am_ws_load · Subscribe to an event with a can user connect code · 60 s ### Subscribe : the code reads the database The same, with a can user connect code which also reads the person from the database (`g.sys.db.getAll` with a `find`) before it answers : one read of MongoDB for every subscription. The code ran in a sandbox of the account. Clients / second 2,046 122,868 clients in 60 s, 100 at a time Let in after, p50 45.0ms connected 6.05 ms · TCP 0.23 ms Let in after, p99 69.3ms max 109 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **1.4 vCPU** · Redis **0.2 vCPU** · MongoDB **0.6 vCPU** · sandboxes **1.6 vCPU** · whole server busy **99 %** · load generator busy **11 %** am_ws_load · Subscribe : the code reads the database · 60 s ### Subscribe : the code reads the clock The same, with a can user connect code which reads the time of the machine (`Date.now()`) : code which is not lean, so API Maker runs it in a sandbox of the account. The code ran in a sandbox of the account. Clients / second 4,505 270,567 clients in 60 s, 100 at a time Let in after, p50 20.1ms connected 3.48 ms · TCP 0.23 ms Let in after, p99 30.7ms max 45.7 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **2.5 vCPU** · Redis **0.3 vCPU** · MongoDB **0.0 vCPU** · sandboxes **0.8 vCPU** · whole server busy **98 %** · load generator busy **23 %** am_ws_load · Subscribe : the code reads the clock · 60 s ## Can user connect code An event of the WebSocket Events page can carry a *can user connect code* : API Maker runs it for every subscription to the event, with the tokens of the client in `g.req.auth` and the subscription in `g.req.eventData`, and lets the client subscribe when it returns `{ canConnect: true }`. Three codes were measured : one which reads the person of the token, one which also reads the database, one which reads the clock. **Reads the person of the token** **Can user connect code of the event checked-token : ran in the server** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { // The person of x-am-user-authorization : only somebody who signed in subscribes, from a country we serve. const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; return { canConnect: person.country === 'India', errorText: 'Not available in your country.' }; }; module.exports = main; ``` **Reads the database** **Can user connect code of the event checked-database : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // Still a customer ? One read of the database for every subscription. const rows = await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers', queryParams: { find: { customer_id: person.customer_id } } }); return { canConnect: rows.length === 1 && rows[0].country === 'India', errorText: 'Not a customer any more.' }; }; module.exports = main; ``` **Reads the clock** **Can user connect code of the event checked-sandbox : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // The time of the machine : this code runs in the sandbox of the account. const hour = new Date(Date.now()).getUTCHours(); return { canConnect: person.country === 'India' && hour >= 0, errorText: 'Not available in your country.' }; }; module.exports = main; ``` | Can user connect code | Runs in | Clients / second | Subscribed after, p50 | p99 | Against no code | |---|---|--:|--:|--:|--:| | No code | – | **6,627** | 13.4 ms | 19.3 ms | – | | Reads the person of the token | the server (QuickJS) | **5,533** | 16.0 ms | 23.1 ms | 17 % fewer | | Reads the person from the database | a sandbox of the account | **2,046** | 45.0 ms | 69.3 ms | 69 % fewer | | Reads the clock | a sandbox of the account | **4,505** | 20.1 ms | 30.7 ms | 32 % fewer | Lean code (it only reads what it is handed) runs in the server itself, with QuickJS, on the thread which serves the client. Code which needs more runs in a sandbox of the account : every subscription is then a round trip to the sandbox. ## Notifications With 10,000 clients connected, autocannon makes the HTTP calls which notify them, for 60 seconds, and the clients count what they receive and how late. Each kind of notification is measured twice : at a pace far under what the server takes, which shows how long a notification takes, and with no pace, which shows how many a second the server tells. *Delivery* is the time from the moment autocannon writes the request to the moment the client reads the notification : the HTTP call, API Maker, Redis, and the WebSocket. ### A notification for one person autocannon calls the [emit event WS API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-emit-event-ws-api.html) with both tokens ; every call names another one of the 10,000 connected clients (`recipientId`), which is the only one told. The clients measure how long each notification took from the moment its request was written. **1,000 calls a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 10 connections Notifications / second 991 60,010 received by 10,000 clients Delivery p50 1.04ms average 1.09 ms Delivery p99 2.03ms max 6.07 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.3 vCPU** · Redis **0.0 vCPU** · whole server busy **10 %** · load generator busy **8 %** autocannon · A notification for one person, 1,000 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 13,049 782,930 calls in 60 s, 100 connections Notifications / second 12,791 783,029 received by 10,000 clients Delivery p50 7.43ms average 7.48 ms Delivery p99 11.6ms max 25.8 ms Not delivered 0 0 calls failed (Server during this run) API Maker **3.3 vCPU** · Redis **0.2 vCPU** · MongoDB **0.0 vCPU** · whole server busy **96 %** · load generator busy **32 %** autocannon · A notification for one person, as many as the server takes am_ws_load · what the clients received ### A broadcast 1,000 more clients subscribe to an event without a condition : every call of the emit event WS API reaches all 1,000 of them. **5 calls a second** Calls / second (paced) 5 300 calls in 60 s, 1 connection Notifications / second 4,972 301,000 received by 1,000 clients Delivery p50 8.00ms average 8.50 ms Delivery p99 17.3ms max 35.4 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.1 vCPU** · Redis **0.0 vCPU** · whole server busy **5 %** · load generator busy **6 %** autocannon · A broadcast to 1,000 clients, 5 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 120 7,196 calls in 60 s, 10 connections Notifications / second 117,698 7,205,000 received by 1,000 clients Delivery p50 73.4ms average 72.6 ms Delivery p99 114ms max 150 ms Not delivered 0 0 calls failed (Server during this run) API Maker **3.4 vCPU** · Redis **0.2 vCPU** · MongoDB **0.0 vCPU** · whole server busy **94 %** · load generator busy **41 %** autocannon · A broadcast to 1,000 clients, as many as the server takes am_ws_load · what the clients received ### Rows inserted in a table 100 clients subscribe to the insert API of a table (`SCHEMA_POST_BULK_INSERT` on `inserts_public`, `getEventData: true`) ; autocannon inserts rows of the [dataset](https://apimaker.dev/json/benchmark_dataset.json) through the [insert API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html), and every row saved is told to each of the 100 clients, with its columns. **50 calls a second** Calls / second (paced) 50 3,000 calls in 60 s, 10 connections Notifications / second 4,930 301,000 received by 100 clients Delivery p50 20.7ms average 20.6 ms Delivery p99 34.5ms max 43.2 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · MongoDB **0.1 vCPU** · whole server busy **7 %** · load generator busy **7 %** autocannon · Inserts told to 100 clients, 50 inserts a second am_ws_load · what the clients received **As many as the server takes** Calls / second 779 46,735 calls in 60 s, 100 connections Notifications / second 76,505 4,683,200 received by 100 clients Delivery p50 443ms average 442 ms Delivery p99 519ms max 610 ms Not delivered 0 0 calls failed (Server during this run) API Maker **2.7 vCPU** · Redis **0.2 vCPU** · MongoDB **0.6 vCPU** · whole server busy **95 %** · load generator busy **28 %** autocannon · Inserts told to 100 clients, as many as the server takes am_ws_load · what the clients received ## With every client connected The same runs once more, with 795,888 clients connected and waiting : what a server which is full of WebSocket clients still does. | | No client, or 10,000 | 795,888 clients connected | |---|--:|--:| | A notification for one person, 1,000 a second : delivery p50 | 1.04 ms | **1.03 ms** | | … p99 | 2.03 ms | **1.99 ms** | | A notification for one person, as many as the server takes | 12,791 / s | **9,745 / s** | | Get all with both tokens, 100 connections (autocannon) | 5,268 req/s | **4,185 req/s** | | … latency p50 / p99 | 18 ms / 34 ms | **19 ms / 148 ms** | **Notification, 1,000 a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 10 connections Notifications / second 991 60,006 received by 795,888 clients Delivery p50 1.03ms average 1.08 ms Delivery p99 1.99ms max 7.35 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.9 vCPU** · Redis **0.0 vCPU** · whole server busy **26 %** · load generator busy **11 %** autocannon · A notification for one person, 1,000 a second, every client connected am_ws_load · what the clients received **Notification, as many as the server takes** Calls / second 9,875 592,472 calls in 60 s, 100 connections Notifications / second 9,745 592,572 received by 795,888 clients Delivery p50 8.11ms average 9.93 ms Delivery p99 56.1ms max 226 ms Not delivered 0 0 calls failed (Server during this run) API Maker **3.4 vCPU** · Redis **0.2 vCPU** · MongoDB **0.0 vCPU** · whole server busy **97 %** · load generator busy **39 %** autocannon · A notification for one person, as many as the server takes, every client connected am_ws_load · what the clients received **Get all with both tokens** Requests / second 4,185 251,102 requests in 60 s Latency p50 19ms average 23.4 ms Latency p99 148ms max 339 ms Errors 0 non-2xx, errors, timeouts (Server during this run) API Maker **2.4 vCPU** · Redis **0.1 vCPU** · MongoDB **1.0 vCPU** · whole server busy **99 %** · load generator busy **23 %** autocannon · get all with both tokens · 795,888 WebSocket clients connected ## A restart API Maker was restarted (`systemctl restart api_maker_be`) with 596,916 clients connected : the newest left first, down to 75 % of the 795,888 it held. Every client of a restarted server comes back within the same seconds and waits for its turn with its request in the kernel, about 4 KB each : a server needs that room. It takes what Redis keeps of them out first, then closes every client with the code `1001` (*Server is going away*) ; each client waits one to five seconds, as an application does, connects again with the same tokens and sends its `REGISTER` again. The server which comes back lets 256 clients in at a time and handles the messages of 256 at a time, the others wait for their turn : its memory comes back to what it was, not higher. Clients dropped 596,916 of 596,916 connected All back after 189.1s the restart itself : 46.1 s A client was away, p50 79.1s its own wait of 1 to 5 s counted A client was away, p99 172.5s the longest : 177 s After the restart, with the 596,916 clients back : API Maker 2,039 MB (2,474 MB before it), 2,188 MB of memory available. They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,000 arrived**, in 1.04 ms (p50) and 2.14 ms (p99). A client whose subscription had not come back with it would have been told nothing. ### Every client leaves at once At the end of the run, the 596,916 clients closed their connection in the same second, as when a network or a load balancer in front of the server goes. The server had closed every one of their sockets after **23.4 s**, and Redis held nothing of them any more after **29.1 s**. A socket is closed at once, and Redis is told behind it. ## Questions ### How many WebSocket connections can API Maker hold on 4 dedicated vCPUs and 8 GB ? 795,888 clients were connected at the same time on this server, each with both tokens and a subscription of its own, with MongoDB, Redis and two sandboxes on the same machine. Memory is what ends first : a client costs about 8.7 KB of the server in all. ### How much memory does a WebSocket client cost ? About 8.7 KB : 3.3 KB in the API Maker process, 4.4 KB in the Linux kernel (its socket) and 1.1 KB in Redis (its subscription). Measured between 200,000 and 600,000 clients which wait, each connected with both tokens and one subscription. ### How many clients can connect each second ? 6,627 clients a second connected with both tokens, subscribed and left, 100 at a time ; 12,535 a second without a subscription. With a can user connect code on the event : 5,533 a second. ### How fast does a notification reach a client ? At 1,000 notifications a second, each for one person among 10,000 : 1.04 ms from the HTTP call to the client (p50), 2.03 ms for 99 % of them. With as many calls as the server takes : 12,791 notifications a second. ### Do connected WebSocket clients slow the APIs down ? Get all with both tokens answered 5,268 requests a second with no WebSocket client, and 4,185 with 795,888 clients connected and waiting. A client which waits costs memory ; its CPU is a ping a minute. --- # API Maker WebSocket benchmark : 8 vCPU, 16 GB RAM (Linode dedicated CPU) > API Maker WebSockets on 8 dedicated vCPUs, 16 GB (Linode) : 1,732,035 clients connected at once, 9 KB each, 10,093 new clients a second, with memory and outputs. Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html WebSocket benchmark · Linode (Akamai Cloud) · Dedicated CPU · 14 October 2026 **8 vCPU, 16 GB RAM : 1,732,035 WebSocket clients connected at once.** API Maker 4.0.0 on a Linode Dedicated 16 GB (g6-dedicated-8) : 8 dedicated vCPUs and 16 GB of RAM at $144 a month, its MongoDB and Redis on the same machine. A second server opened WebSocket clients, each with both tokens and a subscription of its own, until the memory of the server was full, while autocannon made the calls which notify them : every run 60 seconds, the memory and CPU of every part sampled each second. Clients connected 1,732,035 the memory was full : 2,050 MB left Memory per client 8.8KB API Maker 3.2 · kernel 4.5 · Redis 1.1 New clients / second 10,093 both tokens and a subscription · 19,391 without one Notification delivered in 0.83ms p50 at 1,000 a second · p99 1.27 ms ## The server | | | |---|---| | Server | Linode (Akamai Cloud), Dedicated 16 GB (g6-dedicated-8), dedicated cpu, $144 / month | | CPU | AMD EPYC 7642 48-Core Processor, 8 dedicated vCPUs (KVM)
KVM guest, 1 thread per core · L1d 512 KiB (8 instances) · L2 4 MiB (8 instances) · L3 128 MiB (8 instances) · BogoMIPS 4600.00 | | Memory | 16 GB (15,991 MB usable), swap 8.5 GB (496 MB of Linode + 8 GB made by the installer) | | Disk, region | 320 GB SSD, Mumbai, India (ap-west) | | System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 | | API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy | | Settings | the defaults of the installer : one worker thread per vCPU, up to 4,093,696 open files for the service (`LimitNOFILE`), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) | | Network limits | as the installer sets them : 4,093,696 connections tracked by the firewall of Linux (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted (`net.core.somaxconn`). The memory of all its TCP connections together : raised by API Maker as the clients came, to 3.9 GB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) | | Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) : on the same server. No other database runs | | Sandboxes | TypeScript on Node.js 24.21.0 (an image of 404 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default) | | Load generator | Dedicated 32 GB (g6-dedicated-16) : AMD EPYC 7642 48-Core Processor, 16 dedicated vCPUs, Ubuntu 24.04.4 LTS. The WebSocket clients : am_ws_load, a program in Rust made for these benchmarks, a socket and a task per client, from 101 addresses of the load generator. The HTTP calls : Node.js 24.21.0, autocannon 8.0.0 | | Network | A VLAN of the same data centre, round trip 0.21 ms (ping) | | Date | 14 October 2026, 03:18 to 04:18 UTC | Only what the run needs was running : API Maker and its two sandboxes, its MongoDB and its Redis. API Maker was restarted and the swap emptied before the run. How every number was taken : [How the WebSocket benchmarks are made](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html). The APIs of this server : [8 vCPU · 16 GB, API benchmark](https://docs.apimaker.dev/v4/docs/benchmarks/linode-dedicated-8-vcpu-16gb.html). ## The data - **The clients** connect to `ws://:38246/?x-am-authorization=&x-am-user-authorization=` : the token of an API user, and the token of a person, a row of the `customers` table of the [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`) made by a DB token generator. API Maker checks both. - **A subscription** is one `REGISTER` for the custom WebSocket event `order-updates` with a condition of its own : `{ conditionType: 'RESPONSE', criteria: { recipientId: '' } }`. It is the way [one notification reaches one person](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html). - **A notification** for one person is 141 bytes ; a row of the dataset told to the clients of a table is 321 bytes. - **The tables** are the ones of the [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html#the-data), in MongoDB : ten rows of customers, ten columns each. ## Results at a glance **New clients per second** [Connect : the token of the API user](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#connect-1-token) · 21,780 [Connect : both tokens](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#connect-2-tokens) · 19,391 [Connect with both tokens and subscribe](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#subscribe) · 10,093 [Subscribe to an event with a can user connect code](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#can-user-connect) · the code ran in the server · 8,963 [Subscribe : the code reads the database](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#can-user-connect-database) · the code ran in the sandbox · 3,919 [Subscribe : the code reads the clock](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#can-user-connect-sandbox) · the code ran in the sandbox · 7,543 100 clients at a time connect, are let in and leave, for 60 seconds. **Notifications per second** [A notification for one person](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#one-person) · 21,252 calls / second · 21,001 [A broadcast](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#broadcast) · 209 calls / second · 206,570 [Rows inserted in a table](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html#insert) · 1,350 calls / second · 132,499 As many calls as the server takes : what the clients received each second. ## How many clients fit Clients connect 8,000 a second, level after level, each with both tokens and a subscription of its own ; at each level they wait 30 seconds while the server is sampled (the level the run stops at, 60). The run stopped adding clients at **1,732,035** : the memory of the server was full. 1,964 MB of its 15,992 MB were still counted as available, and Linux had moved 1,187 MB to the swap since the clients began to connect, to make that room : 777 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server). > Diagram : Clients connected and memory used during the run > > The run of this server, second after second : the WebSocket clients connected, up to 1,732,035, and the memory the server used, up to 14,469 MB of 15,991 MB. API Maker · MongoDB of API Maker · Redis · Sandboxes · Linux : its sockets, Docker, the rest · Available No client at rest 10,000 clients connected 100,000 clients connected 200,000 clients connected 400,000 clients connected 600,000 clients connected 800,000 clients connected 1,000,000 clients connected 1,200,000 clients connected 1,400,000 clients connected 1,600,000 clients connected 1,732,035 clients connected | Clients | API Maker | Redis | Kernel | MongoDB | Sandboxes | Server, used | Available | Swap | CPU busy | |---|--:|--:|--:|--:|--:|--:|--:|--:|--:| | None (at rest) | 117 | 1 | 245 | 124 | 55 | **964** | 15,028 | 0 | 0.5 % | | **10,000** | 171 | 12 | 375 | 162 | 901 | **1,994** | 13,998 | 0 | 0.6 % | | **100,000** | 452 | 103 | 699 | 243 | 900 | **2,721** | 13,271 | 0 | 1.0 % | | **200,000** | 765 | 204 | 1,146 | 239 | 900 | **3,503** | 12,490 | 0 | 2.4 % | | **400,000** | 1,413 | 404 | 2,039 | 239 | 900 | **5,096** | 10,895 | 0 | 3.7 % | | **600,000** | 2,067 | 625 | 2,928 | 239 | 900 | **6,720** | 9,272 | 0 | 6.8 % | | **800,000** | 2,660 | 810 | 3,819 | 239 | 900 | **8,167** | 7,825 | 0 | 9.8 % | | **1,000,000** | 3,361 | 995 | 4,711 | 239 | 900 | **9,810** | 6,182 | 0 | 12.6 % | | **1,200,000** | 3,970 | 1,249 | 5,588 | 239 | 900 | **11,403** | 4,589 | 0 | 14.6 % | | **1,400,000** | 4,566 | 1,430 | 6,429 | 239 | 900 | **12,886** | 3,106 | 0 | 13.7 % | | **1,600,000** | 5,143 | 1,619 | 7,281 | 178 | 625 | **13,924** | 2,068 | 322 | 16.5 % | | **1,732,035** | 5,179 | 1,736 | 7,839 | 52 | 334 | **13,942** | 2,050 | 1,525 | 21.8 % | Memory in MB. API Maker is the resident memory of its process ; Redis is the memory of its data (`used_memory`) ; the kernel of Linux keeps every socket and every tracked connection in its slab ; a container is counted the way `docker stats` counts it. CPU busy is the whole server while the clients wait : the server pings every client once a minute, and each answers. ### Memory when the server is full With **1,732,035 clients** connected and waiting, of the 15,992 MB of the server : | Part | At rest, no client | 1,732,035 clients | More | |---|--:|--:|--:| | **API Maker** (process) | 117 MB | **5,179 MB** | + 5,062 MB | | Redis (container) | 3 MB | **1,633 MB** | + 1,630 MB | | Linux kernel : sockets, tracked connections (slab) | 245 MB | **7,839 MB** | + 7,594 MB | | MongoDB of API Maker (container) | 124 MB | **52 MB** | − 71 MB | | Sandboxes (2 containers) | 55 MB | **334 MB** | + 279 MB | | **Whole server**, used | 964 MB | **13,942 MB** | + 12,978 MB | | Available | 15,028 MB | **2,050 MB** | | | Swap used | 0 MB | **1,525 MB** | | | Open files of API Maker | 28 | **1,732,075** | | | Keys of Redis · channels it listens on | 13 · 5 | **3,464,086 · 1,732,040** | | MongoDB and the sandboxes grew during the runs before this one (the inserts, the code of the events), not with the clients. ### What a client costs Between 400,000 and 1,400,000 clients (6 levels), each client more cost the server **8.8 KB** : | Where | Per client | What it is | |---|--:|---| | **API Maker** | **3.2 KB** | The client itself : its socket and the one task which reads it, its tokens and what they said, its subscription and the channel it is told on. | | Linux kernel | 4.5 KB | The TCP socket, and the entry of the connection in the table of the firewall (Docker makes Linux track every connection). | | Redis | 1.1 KB | The subscription : its key, its place in the list of its condition, and the channel API Maker listens on. | | **In all** | **8.8 KB** | 118,886 clients per GB of memory. | Measured over the levels at which nothing was in the swap. The memory the whole server had available went down by 8.0 KB per client : MongoDB, the sandboxes and the cache of files give some back while the clients take theirs. ## One more subscription, and a broadcast to everybody With 200,000 clients connected, every client sent a second `REGISTER`, for an event without a condition (`announcements`), 8,000 of them a second : 200,000 were taken in 25.0 s. They waited 30 seconds with two subscriptions each, were told 3 broadcasts, one call of the emit event WS API each, and took the subscription back with `UNREGISTER`. One subscription more 1.2KB per client : API Maker 0.5 KB · Redis 0.8 KB A broadcast to 200k clients 1.79s until the last client read it Half of them told after 1,230ms the first after 698 ms Clients told / second 111,544 one call, every client | Broadcast | Clients told | The call answered after | The first client | Half of them | 99 % of them | The last one | Clients told a second | |---|--:|--:|--:|--:|--:|--:|--:| | 1 | 200,000 of 200,000 | 1.80 s | 698 ms | 1,230 ms | 1,777 ms | **1,793 ms** | 111,544 | | 2 | 200,000 of 200,000 | 1.83 s | 667 ms | 1,238 ms | 1,792 ms | **1,828 ms** | 109,419 | | 3 | 200,000 of 200,000 | 1.84 s | 698 ms | 1,252 ms | 1,822 ms | **1,837 ms** | 108,870 | One call of the emit event WS API tells every client : API Maker asks Redis for the clients of the event, publishes the notification for each of them, and the server which holds a client sends it. The times are counted from the moment the call is written to the moment a client reads its notification. | Memory, 200,000 clients | One subscription each | Two subscriptions each | A subscription more, per client | |---|--:|--:|--:| | API Maker | 765 MB | 855 MB | 0.5 KB | | Redis (its data) | 204 MB | 349 MB | 0.8 KB | | Keys of Redis · channels | 400,016 · 200,005 | 600,017 · 400,005 | | | **Whole server**, less available | | | **1.2 KB** | ## New clients per second How many clients a second the server lets in : 100 clients at a time connect, are let in and leave, one after the other, for 60 seconds (after 5 seconds which are not counted). It is what a server faces when its clients all come back, after a deployment or a network cut. The times are counted from the start of the TCP connection. ### Connect : the token of the API user A client connects with `x-am-authorization` alone, is told `CONNECTED`, and leaves. API Maker checks the token of the API user and finds its groups : what every WebSocket client costs before it asks for anything. Clients / second 21,780 1,308,117 clients in 60 s, 100 at a time Let in after, p50 2.89ms connected 2.89 ms · TCP 0.25 ms Let in after, p99 5.26ms max 18.6 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **7.0 vCPU** · MongoDB **0.0 vCPU** · whole server busy **92 %** · load generator busy **38 %** am_ws_load · Connect : the token of the API user · 60 s ### Connect : both tokens A client connects with `x-am-authorization` and `x-am-user-authorization`, is told `CONNECTED`, and leaves. Both tokens are checked : the one of the API user, and the one of a person, made by the DB token generator of the account. Clients / second 19,391 1,164,622 clients in 60 s, 100 at a time Let in after, p50 3.24ms connected 3.24 ms · TCP 0.26 ms Let in after, p99 5.98ms max 18.1 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **7.0 vCPU** · MongoDB **0.0 vCPU** · whole server busy **92 %** · load generator busy **35 %** am_ws_load · Connect : both tokens · 60 s ### Connect with both tokens and subscribe The whole of what an application does : connect with both tokens, `CONNECTED`, one `REGISTER` for a custom WebSocket event with a condition of its own (`recipientId` : its user id), the answer, then leave. API Maker checks the groups and the auth provider of the event, keeps the subscription in Redis and listens on its channel ; when the client leaves, all of it is taken back. Clients / second 10,093 606,180 clients in 60 s, 100 at a time Let in after, p50 8.85ms connected 2.26 ms · TCP 0.24 ms Let in after, p99 12.8ms max 22.1 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **5.5 vCPU** · Redis **0.5 vCPU** · MongoDB **0.0 vCPU** · whole server busy **85 %** · load generator busy **21 %** am_ws_load · Connect with both tokens and subscribe · 60 s ### Subscribe to an event with a can user connect code The same, on an event whose *can user connect code* decides who may subscribe : it reads the person of `x-am-user-authorization` from `g.req.auth`. The code ran in the server itself (lean code, QuickJS). Clients / second 8,963 538,318 clients in 60 s, 100 at a time Let in after, p50 10.0ms connected 2.45 ms · TCP 0.24 ms Let in after, p99 14.5ms max 29.3 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **5.8 vCPU** · Redis **0.5 vCPU** · whole server busy **87 %** · load generator busy **17 %** am_ws_load · Subscribe to an event with a can user connect code · 60 s ### Subscribe : the code reads the database The same, with a can user connect code which also reads the person from the database (`g.sys.db.getAll` with a `find`) before it answers : one read of MongoDB for every subscription. The code ran in a sandbox of the account. Clients / second 3,919 235,367 clients in 60 s, 100 at a time Let in after, p50 23.7ms connected 3.11 ms · TCP 0.22 ms Let in after, p99 38.4ms max 57.0 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **2.7 vCPU** · Redis **0.3 vCPU** · MongoDB **1.2 vCPU** · sandboxes **3.0 vCPU** · whole server busy **95 %** · load generator busy **7 %** am_ws_load · Subscribe : the code reads the database · 60 s ### Subscribe : the code reads the clock The same, with a can user connect code which reads the time of the machine (`Date.now()`) : code which is not lean, so API Maker runs it in a sandbox of the account. The code ran in a sandbox of the account. Clients / second 7,543 453,034 clients in 60 s, 100 at a time Let in after, p50 12.0ms connected 2.20 ms · TCP 0.22 ms Let in after, p99 19.4ms max 31.7 ms Refused or lost 0 not connected, not subscribed, no answer (Server during this run) API Maker **4.9 vCPU** · Redis **0.4 vCPU** · MongoDB **0.0 vCPU** · sandboxes **1.4 vCPU** · whole server busy **92 %** · load generator busy **16 %** am_ws_load · Subscribe : the code reads the clock · 60 s ## Can user connect code An event of the WebSocket Events page can carry a *can user connect code* : API Maker runs it for every subscription to the event, with the tokens of the client in `g.req.auth` and the subscription in `g.req.eventData`, and lets the client subscribe when it returns `{ canConnect: true }`. Three codes were measured : one which reads the person of the token, one which also reads the database, one which reads the clock. **Reads the person of the token** **Can user connect code of the event checked-token : ran in the server** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { // The person of x-am-user-authorization : only somebody who signed in subscribes, from a country we serve. const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; return { canConnect: person.country === 'India', errorText: 'Not available in your country.' }; }; module.exports = main; ``` **Reads the database** **Can user connect code of the event checked-database : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // Still a customer ? One read of the database for every subscription. const rows = await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers', queryParams: { find: { customer_id: person.customer_id } } }); return { canConnect: rows.length === 1 && rows[0].country === 'India', errorText: 'Not a customer any more.' }; }; module.exports = main; ``` **Reads the clock** **Can user connect code of the event checked-sandbox : ran in the sandbox** ```typescript import * as T from 'types'; async function main(g: T.IAMGlobal) { const person = g.req.auth.authAMDB; if (!person) return { canConnect: false, errorText: 'Sign in first.' }; // The time of the machine : this code runs in the sandbox of the account. const hour = new Date(Date.now()).getUTCHours(); return { canConnect: person.country === 'India' && hour >= 0, errorText: 'Not available in your country.' }; }; module.exports = main; ``` | Can user connect code | Runs in | Clients / second | Subscribed after, p50 | p99 | Against no code | |---|---|--:|--:|--:|--:| | No code | – | **10,093** | 8.85 ms | 12.8 ms | – | | Reads the person of the token | the server (QuickJS) | **8,963** | 10.0 ms | 14.5 ms | 11 % fewer | | Reads the person from the database | a sandbox of the account | **3,919** | 23.7 ms | 38.4 ms | 61 % fewer | | Reads the clock | a sandbox of the account | **7,543** | 12.0 ms | 19.4 ms | 25 % fewer | Lean code (it only reads what it is handed) runs in the server itself, with QuickJS, on the thread which serves the client. Code which needs more runs in a sandbox of the account : every subscription is then a round trip to the sandbox. ## Notifications With 10,000 clients connected, autocannon makes the HTTP calls which notify them, for 60 seconds, and the clients count what they receive and how late. Each kind of notification is measured twice : at a pace far under what the server takes, which shows how long a notification takes, and with no pace, which shows how many a second the server tells. *Delivery* is the time from the moment autocannon writes the request to the moment the client reads the notification : the HTTP call, API Maker, Redis, and the WebSocket. ### A notification for one person autocannon calls the [emit event WS API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-emit-event-ws-api.html) with both tokens ; every call names another one of the 10,000 connected clients (`recipientId`), which is the only one told. The clients measure how long each notification took from the moment its request was written. **1,000 calls a second** Calls / second (paced) 1,000 60,001 calls in 60 s, 10 connections Notifications / second 983 60,011 received by 10,000 clients Delivery p50 0.83ms average 0.85 ms Delivery p99 1.27ms max 4.99 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.4 vCPU** · Redis **0.0 vCPU** · whole server busy **6 %** · load generator busy **3 %** autocannon · A notification for one person, 1,000 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 21,252 1,275,084 calls in 60 s, 100 connections Notifications / second 21,001 1,275,184 received by 10,000 clients Delivery p50 4.50ms average 4.53 ms Delivery p99 6.80ms max 15.5 ms Not delivered 0 0 calls failed (Server during this run) API Maker **6.5 vCPU** · Redis **0.3 vCPU** · whole server busy **91 %** · load generator busy **24 %** autocannon · A notification for one person, as many as the server takes am_ws_load · what the clients received ### A broadcast 1,000 more clients subscribe to an event without a condition : every call of the emit event WS API reaches all 1,000 of them. **5 calls a second** Calls / second (paced) 5 300 calls in 60 s, 1 connection Notifications / second 4,931 301,000 received by 1,000 clients Delivery p50 6.53ms average 7.08 ms Delivery p99 14.0ms max 29.9 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.1 vCPU** · whole server busy **2 %** · load generator busy **3 %** autocannon · A broadcast to 1,000 clients, 5 a second am_ws_load · what the clients received **As many as the server takes** Calls / second 209 12,537 calls in 60 s, 10 connections Notifications / second 206,570 12,545,000 received by 1,000 clients Delivery p50 38.9ms average 39.0 ms Delivery p99 60.3ms max 92.2 ms Not delivered 0 0 calls failed (Server during this run) API Maker **6.3 vCPU** · Redis **0.3 vCPU** · whole server busy **87 %** · load generator busy **29 %** autocannon · A broadcast to 1,000 clients, as many as the server takes am_ws_load · what the clients received ### Rows inserted in a table 100 clients subscribe to the insert API of a table (`SCHEMA_POST_BULK_INSERT` on `inserts_public`, `getEventData: true`) ; autocannon inserts rows of the [dataset](https://apimaker.dev/json/benchmark_dataset.json) through the [insert API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html), and every row saved is told to each of the 100 clients, with its columns. **50 calls a second** Calls / second (paced) 50 3,000 calls in 60 s, 10 connections Notifications / second 4,931 301,000 received by 100 clients Delivery p50 12.9ms average 12.8 ms Delivery p99 19.8ms max 23.6 ms Not delivered 0 0 calls failed (Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · MongoDB **0.1 vCPU** · whole server busy **4 %** · load generator busy **5 %** autocannon · Inserts told to 100 clients, 50 inserts a second am_ws_load · what the clients received **As many as the server takes** Calls / second 1,350 81,024 calls in 60 s, 100 connections Notifications / second 132,499 8,112,100 received by 100 clients Delivery p50 257ms average 256 ms Delivery p99 299ms max 339 ms Not delivered 0 0 calls failed (Server during this run) API Maker **5.2 vCPU** · Redis **0.2 vCPU** · MongoDB **1.1 vCPU** · whole server busy **88 %** · load generator busy **20 %** autocannon · Inserts told to 100 clients, as many as the server takes am_ws_load · what the clients received ## With every client connected The same runs once more, with 1,732,035 clients connected and waiting : what a server which is full of WebSocket clients still does. | | No client, or 10,000 | 1,732,035 clients connected | |---|--:|--:| | A notification for one person, 1,000 a second : delivery p50 | 0.83 ms | **0.87 ms** | | … p99 | 1.27 ms | **1.47 ms** | | A notification for one person, as many as the server takes | 21,001 / s | **15,938 / s** | | Get all with both tokens, 100 connections (autocannon) | 9,672 req/s | **7,305 req/s** | | … latency p50 / p99 | 10 ms / 19 ms | **10 ms / 92 ms** | **Notification, 1,000 a second** Calls / second (paced) 1,000 60,000 calls in 60 s, 10 connections Notifications / second 983 60,010 received by 1,732,035 clients Delivery p50 0.87ms average 0.90 ms Delivery p99 1.47ms max 10.7 ms Not delivered 0 0 calls failed (Server during this run) API Maker **1.7 vCPU** · Redis **0.0 vCPU** · whole server busy **23 %** · load generator busy **10 %** autocannon · A notification for one person, 1,000 a second, every client connected am_ws_load · what the clients received **Notification, as many as the server takes** Calls / second 16,124 967,389 calls in 60 s, 100 connections Notifications / second 15,938 967,489 received by 1,732,035 clients Delivery p50 4.78ms average 6.02 ms Delivery p99 50.5ms max 209 ms Not delivered 0 0 calls failed (Server during this run) API Maker **6.6 vCPU** · Redis **0.3 vCPU** · MongoDB **0.0 vCPU** · whole server busy **92 %** · load generator busy **34 %** autocannon · A notification for one person, as many as the server takes, every client connected am_ws_load · what the clients received **Get all with both tokens** Requests / second 7,305 438,273 requests in 60 s Latency p50 10ms average 13.19 ms Latency p99 92ms max 289 ms Errors 0 non-2xx, errors, timeouts (Server during this run) API Maker **4.9 vCPU** · Redis **0.1 vCPU** · MongoDB **1.9 vCPU** · whole server busy **96 %** · load generator busy **23 %** autocannon · get all with both tokens · 1,732,035 WebSocket clients connected ## Questions ### How many WebSocket connections can API Maker hold on 8 dedicated vCPUs and 16 GB ? 1,732,035 clients were connected at the same time on this server, each with both tokens and a subscription of its own, with MongoDB, Redis and two sandboxes on the same machine. Memory is what ends first : a client costs about 8.8 KB of the server in all. ### How much memory does a WebSocket client cost ? About 8.8 KB : 3.2 KB in the API Maker process, 4.5 KB in the Linux kernel (its socket) and 1.1 KB in Redis (its subscription). Measured between 400,000 and 1,400,000 clients which wait, each connected with both tokens and one subscription. ### How many clients can connect each second ? 10,093 clients a second connected with both tokens, subscribed and left, 100 at a time ; 19,391 a second without a subscription. With a can user connect code on the event : 8,963 a second. ### How fast does a notification reach a client ? At 1,000 notifications a second, each for one person among 10,000 : 0.83 ms from the HTTP call to the client (p50), 1.27 ms for 99 % of them. With as many calls as the server takes : 21,001 notifications a second. ### Do connected WebSocket clients slow the APIs down ? Get all with both tokens answered 9,672 requests a second with no WebSocket client, and 7,305 with 1,732,035 clients connected and waiting. A client which waits costs memory ; its CPU is a ping a minute.