---
title: "Monitoring latency: Cloudflare Workers vs Fly vs Koyeb vs Railway vs Render"
url: "https://www.openstatus.dev/blog/monitoring-latency-cf-workers-fly-koyeb-raylway-render"
date: "2024-02-19"
author: "Thibault Le Ouay Ducasse"
description: "We benchmarked latency across 5 cloud providers from 6 global locations over 2 weeks. Cloudflare Workers averaged 182ms, Fly.io 61ms (warm), Railway 381ms, Koyeb 539ms, and Render 451ms. Full timing breakdowns included."
category: "education"
image: "https://www.openstatus.dev/assets/posts/monitoring-latency/all-hosting-providers.png"
---

> ⚠️ We are using the default settings for each provider and conducting
> datacenter to datacenter requests. A real-world application's results are
> going to be different. ⚠️

You want to know which cloud providers offer the lowest latency?

In this post, I compare the latency of
[Cloudflare Workers](#cloudflare-workers), [Fly](#flyio), [Koyeb](#koyeb),
[Railway](#railway) and [Render](#render) using
[openstatus](https://www.openstatus.dev).

I deployed the application on the cheapest or free tier offered by each
provider.

For this test, I used a basic [Hono](https://hono.dev) server that returns a
simple text response.

```js
const app = new Hono();
app.use("*", logger());

app.use("*", poweredBy());

app.get("/", (c) => {
  return c.text(
    "Just return the desired http status code, e.g. /404 🤯 \nhttps://www.openstatus.dev",
  );
});
```

You can find the code in the [`status-code` repository](https://github.com/openstatusHQ/status-code), it’s
open source 😉.

Openstatus monitored our endpoint every **10 minutes** from **6 locations**
located in Amsterdam, Ashburn, Hong Kong, Johannesburg, Sao Paulo and Sydney.

It's a good way to test our own product and improve it.

Let's analyze the data from the past two weeks.

## Cloudflare workers

Cloudflare Workers is a serverless platform by Cloudflare. It lets you build new
applications using JavaScript/Typescript. You can deploy up to 100 worker
scripts for free, running on more than 275 network locations.

### Latency metrics

**100**% UPTIME

**0**# FAILS

**10,956**# PINGS

**182**ms AVG

**138**ms P75

**695**ms P90

**778**ms P95

**991**ms P99

### Timing metrics

| Region | DNS (ms) | Connection (ms) | TLS Handshake (ms) | TTFB (ms) | Transfert (ms) |
| --- | --- | --- | --- | --- | --- |
| AMS | 17 | 2 | 17 | 27 | 0 |
| GRU | 38 | 2 | 13 | 28 | 0 |
| HKG | 19 | 2 | 13 | 29 | 0 |
| IAD | 24 | 1 | 14 | 30 | 0 |
| JNB | 123 | 168 | 182 | 185 | 0 |
| SYD | 51 | 1 | 11 | 25 | 0 |

I can notice that Johannesburg's latency is about ten times higher than that of
the other monitors.

### Headers

From the Cloudflare request I can get the location of the workers that handle
the request, with `Cf-ray` in the headers response.

| Checker region | Workers region | number of request |
| --- | --- | --- |
| HKG | HKG | 1831 |
| SYD | SYD | 1831 |
| AMS | AMS | 1831 |
| IAD | IAD | 1831 |
| GRU | GRU | 1791 |
| GRU | GIG | 40 |
| JNB | AMS | 741 |
| JNB | MUC | 4 |
| JNB | HKG | 5 |
| JNB | SIN | 6 |
| JNB | NRT | 8 |
| JNB | EWR | 10 |
| JNB | CDG | 82 |
| JNB | FRA | 276 |
| JNB | LHR | 699 |
| JNB | AMS | 741 |

I can see all the request from JNB is never routed to a nearby data-center.

Apart from the strange routing error in Johannesburg, Cloudflare workers are
fast worldwide.

I have not experienced any cold start issues.

## Fly.io

Fly.io simplifies deploying and running server-side applications globally.
Developers can deploy their applications near users worldwide for low latency
and high performance. It uses a lightweight Firecracker VM to easily deploy
Docker images.

### Latency metrics

**100**% UPTIME

**0**# FAILS

**10,952**# PINGS

**1,471**ms AVG

**1,514**ms P75

**1,555**ms P90

**1,626**ms P95

**2,547**ms P99

### Timing metrics

| Region | DNS (ms) | Connection (ms) | TLS Handshake (ms) | TTFB (ms) | Transfert (ms) |
| --- | --- | --- | --- | --- | --- |
| AMS | 6 | 1 | 8 | 1469 | 0 |
| GRU | 5 | 0 | 4 | 1431 | 0 |
| HKG | 4 | 0 | 5 | 1473 | 0 |
| IAD | 3 | 0 | 5 | 1470 | 0 |
| JNB | 24 | 0 | 5 | 1423 | 0 |
| SYD | 3 | 0 | 3 | 1489 | 0 |

The DNS is fast, our checker is attempting to connect to a region in the same
data center, but our machine's cold start is slowing us down, leading to the
high TTFB.

Here’s our config for Fly.io:

```toml
app = 'statuscode'
primary_region = 'ams'

[build]
  dockerfile = "./Dockerfile"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0
  processes = ['app']

[[vm]]
  cpu_kind = 'shared'
  cpus = 1
  memory_mb = 256
```

The primary region of our server is Amsterdam, and the fly instances is getting
paused after a period of inactivity.

The machine starts slowly, as indicated by the logs showing a start time of
`1.513643778s.`

```
2024-02-14T11:24:16.107 proxy[286560ea703108] ams [info] Starting machine

2024-02-14T11:24:16.322 app[286560ea703108] ams [info] [ 0.035736] PCI: Fatal: No config space access function found

2024-02-14T11:24:16.533 app[286560ea703108] ams [info] INFO Starting init (commit: bfa79be)...

2024-02-14T11:24:16.546 app[286560ea703108] ams [info] INFO Preparing to run: `/usr/local/bin/docker-entrypoint.sh bun start` as root

2024-02-14T11:24:16.558 app[286560ea703108] ams [info] INFO [fly api proxy] listening at /.fly/api

2024-02-14T11:24:16.565 app[286560ea703108] ams [info] 2024/02/14 11:24:16 listening on [fdaa:3:2ef:a7b:10c:3c9a:5b4:2]:22 (DNS: [fdaa::3]:53)

2024-02-14T11:24:16.611 app[286560ea703108] ams [info] $ bun src/index.ts

2024-02-14T11:24:16.618 runner[286560ea703108] ams [info] Machine started in 460ms

2024-02-14T11:24:17.621 proxy[286560ea703108] ams [info] machine started in 1.513643778s

2024-02-14T11:24:17.628 proxy[286560ea703108] ams [info] machine became reachable in 7.03669ms
```

#### Openstatus Prod metrics

If you update your fly.toml file to include the following, you can get the zero
cold start and achieve a better latency.

```
  min_machines_running = 1
```

This is our data for our production server deploy on Fly.io.

**100**% UPTIME

**0**# FAILS

**12,076**# PINGS

**61**ms AVG

**67**ms P75

**164**ms P90

**198**ms P95

**327**ms P99

> We use Fly.io in production, and the machine never sleeps, yielding much
> better results.

## Koyeb

Koyeb is a developer-friendly serverless platform that allows for global app
deployment without the need for operations, servers, or infrastructure
management. Koyeb offers a free Starter plan that includes one Web Service, one
Database service. The platform focuses on ease of deployment and scalability for
developers

### Latency metrics

**100**% UPTIME

**0**# FAILS

**10,955**# PINGS

**539**ms AVG

**738**ms P75

**881**ms P90

**1,013**ms P95

**1,525**ms P99

### Timing metrics

| Region | DNS (ms) | Connection (ms) | TLS Handshake (ms) | TTFB (ms) | Transfert (ms) |
| --- | --- | --- | --- | --- | --- |
| AMS | 50 | 2 | 17 | 107 | 0 |
| GRU | 139 | 65 | 75 | 407 | 0 |
| HKG | 48 | 2 | 13 | 321 | 0 |
| IAD | 35 | 1 | 12 | 129 | 0 |
| JNB | 298 | 1 | 11 | 720 | 0 |
| SYD | 97 | 1 | 10 | 711 | 0 |

### Headers

The request headers show that none of our requests are cached. They contain
`cf-cache-status: dynamic`. Cloudflare handles the Koyeb edge layer.
https://www.koyeb.com/blog/building-a-multi-region-service-mesh-with-kuma-envoy-anycast-bgp-and-mtls

Our requests follow this route:

```
Cf workers -> koyeb Global load balancer -> koyeb backend
```

Let's see where did we hit the cf workers

| Checker region | Workers region | number of request |
| --- | --- | --- |
| AMS | AMS | 1866 |
| GRU | GRU | 504 |
| GRU | IAD | 38 |
| GRU | MIA | 688 |
| GRU | EWR | 337 |
| GRU | CIG | 299 |
| HKG | HKG | 1866 |
| IAD | IAD | 1866 |
| JNB | JNB | 1861 |
| JNB | AMS | 1 |
| SYD | SYD | 1866 |

Koyeb Global Load Balancer region we hit:

| Checker region | Koyeb Global Load Balancer | number of request |
| --- | --- | --- |
| AMS | FRA1 | 1866 |
| GRU | WAS1 | 1866 |
| HKG | SIN1 | 1866 |
| IAD | WAS1 | 1866 |
| JNB | PAR1 | 4 |
| JNB | SIN1 | 1864 |
| JNB | FRA1 | 1 |
| JNB | SIN1 | 1866 |

I have deployed our app in the Frankfurt data-center.

## Railway

Railway is a cloud platform designed for building, shipping, and monitoring
applications without the need for Platform Engineers. It simplifies the
application development process by offering seamless deployment and monitoring
capabilities.

### Latency metrics

**99.991**% UPTIME

**1**# FAILS

**10,955**# PINGS

**381**ms AVG

**469**ms P75

**653**ms P90

**661**ms P95

**850**ms P99

### Timing metrics

| Region | DNS (ms) | Connection (ms) | TLS Handshake (ms) | TTFB (ms) | Transfert (ms) |
| --- | --- | --- | --- | --- | --- |
| AMS | 9 | 21 | 18 | 158 | 0 |
| GRU | 14 | 115 | 127 | 178 | 0 |
| HKG | 8 | 45 | 54 | 225 | 0 |
| IAD | 7 | 2 | 14 | 65 | 0 |
| JNB | 18 | 193 | 178 | 319 | 0 |
| SYD | 21 | 108 | 105 | 280 | 0 |

### Headers

The headers don't provide any information.

Railway is using Google Cloud Platform. It’s the only service that does not
allow us to pick a specific region on the free plan. Our test app will be
located to `us-west1` Portland, Oregon. We can see that the latency is the
lowest in IAD.

By default our app did not scale down to 0. It was always running. We don't have
any cold start.

## Render

Render is a platform that simplifies deploying and scaling web applications and
services. It offers features like automated SSL, automatic scaling, native
support for popular frameworks, and one-click deployments from Git. The platform
focuses on simplicity and developer productivity.

### Latency metrics

**99.89**% UPTIME

**12**# FAILS

**10,946**# PINGS

**451**ms AVG

**447**ms P75

**591**ms P90

**707**ms P95

**902**ms P99

### Timing metrics

| Region | DNS (ms) | Connection (ms) | TLS Handshake (ms) | TTFB (ms) | Transfert (ms) |
| --- | --- | --- | --- | --- | --- |
| AMS | 20 | 2 | 7 | 107 | 0 |
| GRU | 61 | 2 | 6 | 407 | 0 |
| HKG | 76 | 2 | 6 | 321 | 0 |
| IAD | 15 | 1 | 5 | 129 | 0 |
| JNB | 36 | 161 | 167 | 720 | 0 |
| SYD | 103 | 1 | 4 | 711 | 0 |

### Headers

The headers don't provide any information.

I have deployed our app in the Frankfurt data-center.

According to the Render docs, the free tier will shut down the service after 15
minutes of inactivity. However, our app is being accessed by a monitor every 10
minutes. We should never scale down to 0.

```
Render spins down a Free web service that goes 15 minutes without receiving inbound traffic. Render spins the service back up whenever it next receives a request to process.
```

I think the failures are due to the cold start of our app. We have a default
timeout of 30s and the render app takes up to 50s to start.We might have hit an
inflection point between cold and warm.

## Conclusion

Here are the results of our test:

| Provider | Uptime | Fails Ping | Total Pings | AVG latency (ms) | P75 (ms) | P90 (ms) | P95 (ms) | P99 (ms) |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| CF Workers | 100 | 0 | 10 | 956 | 182 | 138 | 690 | 778 |
| Fly.io | 100 | 0 | 10 | 952 | 1 | 471 | 1 | 514 |
| Koyeb | 100 | 0 | 10 | 955 | 536 | 738 | 881 | 1 |
| Railway | 99.991 | 1 | 10 | 955 | 381 | 469 | 653 | 661 |
| Render | 99.89 | 12 | 10 | 946 | 451 | 447 | 591 | 707 |

If you value low latency, Cloudflare Workers are the best option for fast global
performance without cold start issues. They deploy your app worldwide
efficiently.

For multi-region deployment, check out Koyeb and Fly.io.

For specific region deployment, Railway and Render are good choices.

Choosing a cloud provider involves considering not just latency but also user
experience and pricing.

We use Fly.io in production and are satisfied with it.

#### Vercel

I haven't included Vercel in this test. But we have a blog post comparing [Vercel Serverless vs Edge vs Serverless](/blog/monitoring-latency-vercel-edge-vs-serverless).

Want the same measurement for your own endpoint? Run it through the
[website speed test](/play/checker) — 28 regions with the per-phase timing
breakdown, and no account needed.

If you want to monitor your API or website, create an account on
[openstatus](/app/sign-up?ref=blog-monitoring).

## Frequently asked questions

<details>
  <summary>Which cloud provider has the lowest latency?</summary>
  In our benchmark, Cloudflare Workers had the lowest average latency of the providers left on their default configuration: 182ms across 6 global regions, with a P75 of 138ms. Fly.io was faster still when kept warm — 61ms with min_machines_running=1 — but averaged 1,471ms once cold starts were allowed.
</details>

<details>
  <summary>Does Fly.io have cold start issues?</summary>
  Yes. With auto_stop_machines enabled and min_machines_running=0, Fly.io averaged 1,471ms due to cold starts (~1.5s machine boot time). Setting min_machines_running=1 eliminates cold starts and brings the average down to 61ms.
</details>

<details>
  <summary>How does Cloudflare Workers latency compare to Railway and Render?</summary>
  Cloudflare Workers averaged 182ms with 100% uptime. Railway averaged 381ms with 99.991% uptime (1 failure). Render averaged 451ms with 99.89% uptime (12 failures). Cloudflare Workers deploy globally to 275+ locations, while Railway and Render run from a single region.
</details>

<details>
  <summary>Which cloud provider had the most downtime in the benchmark?</summary>
  Render had the most failures with 12 failed checks and 99.89% uptime over 2 weeks. Railway had 1 failure (99.991% uptime). Cloudflare Workers, Fly.io, and Koyeb all had 0 failures and 100% uptime.
</details>