EN
Currency:
EUR – €
Choose a currency
  • Euro EUR – €
  • United States dollar USD – $
VAT:
OT 0%
Choose your country (VAT)
  • OT All others 0%

30.10.2026

Which LLM Gateway to Install on Your Server: LiteLLM or OmniRoute

server one
HOSTKEY

Generative models have become more popular than ever, both in Europe and beyond. Naturally, people view them differently: some find them annoying, some are thrilled by the new possibilities for everyday tasks and creative work, and others fear losing their jobs. There is even a wholly irrational view that everything is inexorably heading toward an apocalypse. Still, practically everyone will have to work with generative models sooner or later. Today we look at two approaches to organizing this work and compare LiteLLM and OmniRoute. Both are popular open-source gateways that hide dozens of LLM providers behind a single OpenAI-compatible API endpoint.

The OmniRoute Providers page lists more than 370 providers, from paid APIs to free tiers and subscriptions

Pre-installed LiteLLM and OmniRoute
Order a server with LiteLLM or OmniRoute pre-installed and connect your models immediately after launch.

Summary of Results

We measured how much latency the gateways add to a request, how many requests per second they can sustain, and how much memory and CPU they consume.

With a single worker process, LiteLLM wins on standard requests, while OmniRoute leads on streaming output once its rate-limit protection is turned off. Give LiteLLM a second worker process and it overtakes its competitor in both modes, since OmniRoute cannot make use of a second core.

 

LiteLLM, 1 process

LiteLLM, 2 processes

OmniRoute

Max throughput without streaming, requests per second

71

130

36 (about 56 estimated on identical hardware)

Max throughput with streaming, requests per second

20

38.5

25 (about 37 estimated on identical hardware)

Overhead per standard request, milliseconds

14

15

30

Peak gateway memory, gigabytes

0.9

2.1

1.2

Default settings suitable for a self-hosted model

yes

yes

no, about 1 request per second

Why Put a Gateway in Front of LLMs

When an application talks to a single model from one provider, a gateway is unnecessary. But once there are two providers and five consumers of the models, it is more convenient to have a single endpoint with a unified API format. The gateway decides on its own where to route each request. Through it, teams and services get their own keys, budgets are capped, a fallback model kicks in when the primary one fails, and model spending is tracked centrally. In essence, the gateway acts as a convenient coordinator.

The drawback stems from the same convenience: the chain gains an extra link and a potential point of failure. An LLM response takes seconds, so tens of milliseconds spent in the gateway go unnoticed against that backdrop; but with a hundred concurrent clients a queue builds up, and the model behind the gateway may sit idle. In our test, the model was replaced with an instant mock, so all measured time is attributable to the gateway itself.

How LiteLLM and OmniRoute Differ Architecturally

Both gateways expose a single OpenAI-compatible endpoint, but they grew out of different needs, and it shows in their internals. LiteLLM is usually deployed by an engineering team in front of all of a company’s internal services. Each service gets its own key with a monthly dollar limit, and spending across all keys is collected in Postgres, which makes it possible to see what each department spends. OmniRoute is aimed more at an individual developer working with Claude Code, Codex, or Cursor who wants to plug all their subscriptions into them at once. When one provider’s quota runs out, OmniRoute automatically sends the next request to another provider, and the agent keeps working without reconfiguration.

 

LiteLLM

OmniRoute

Language and runtime

Python, FastAPI

TypeScript, Next.js on Node.js

Storage

Postgres (keys, budgets, and spend log)

Redis and a local data directory

Who deploys it and why

An engineering team, for a company’s internal services

A developer, for their own agents

Routing

Router with retries and fallback models

“Combos” (model chains with automatic failover) and auto models

Scaling

The --num_workers flag and multiple instances

A single Node.js process

Testing

Ready-made performance tests exist only for LiteLLM, and an important caveat is that they were created by the gateway’s own developers. According to their data, four LiteLLM instances in front of a mock OpenAI API handle about 1,170 requests per second and add 8 milliseconds at the 95th percentile. An independent comparison by the agentgateway team offered more hard data: under load, LiteLLM consumed almost 12 GB of memory with 18 worker processes. We found no published tests for OmniRoute, so we built a test bench of two virtual servers. Each ran three programs: the gateway itself, a client generating the load, and a mock imitating the language model. We gave the gateway two CPU cores and the client and mock one core each, so they would not take CPU time away from the gateway and skew the results.

 

LiteLLM server

OmniRoute server

CPU

4 vCPUs, AMD EPYC 7542

4 vCPUs, AMD EPYC 7702P

Memory and swap

7.7 GB, no swap

7.7 GB, 4 GB swap

OS

Ubuntu 24.04

Ubuntu 24.04

Installation

Docker, Postgres 16

Docker, Redis 8, 4.6 GB container memory limit

The test setup is as follows:

The gateway, client, and mock run on the same server, on separate cores

The model mock runs in a separate Docker container on the same network as the gateway and answers any request immediately, returning 50 tokens either as a single response or as fifty streaming chunks. Requests never left the server, so the network between machines had no effect on the results, and nothing had to be exposed externally.

Before measuring each gateway, the client sent the same requests directly to the mock. This baseline shows how many requests per second the client and mock themselves can handle on a given server; everything beyond that is attributable to the gateway. Without the baseline, comparing results from two servers would be unfair, since the OmniRoute server turned out to be roughly 1.5 times slower.

The load client behaves like a typical application waiting for a model response: it sends a request, waits for the full response, and only then sends the next one. As a result, when the gateway is overloaded, latency grows first, and errors appear only if the gateway itself starts refusing service, as happened with OmniRoute on default settings.

Load was applied in steps: first one client, then 10, 50, 100, and 200 concurrent clients, 30 seconds per step with a short warm-up before each, separately for standard and streaming responses. Once per second we recorded CPU usage and memory consumption for each container. Both gateways were left as they are normally deployed according to their documentation: LiteLLM runs a single worker process and stores data in Postgres, OmniRoute uses Redis. We tested LiteLLM 1.106.0 from the main-stable image and OmniRoute 3.8.52; the load client and mock were written in Python 3.12. Each gateway was run twice: OmniRoute with and without rate-limit protection, and LiteLLM with one and two worker processes.

How Much a Gateway Slows Down a Single Request

With a single client and no queue, LiteLLM adds 14 milliseconds to a standard request and OmniRoute adds 30. On a streaming response of 50 chunks the difference almost disappears: the overhead is 45 and 40 milliseconds. If you subtract the standard-request overhead from the streaming overhead and divide by 50, LiteLLM comes out at about 0.6 milliseconds per chunk and OmniRoute at 0.2, three times less. This is a rough estimate, since some of the time may go to setting up the stream itself, and we tested responses of only one length. At this rate, LiteLLM would lengthen a 500-token response from a real model by about 0.3 seconds, and OmniRoute by about 0.1.

LiteLLM handles the request itself more cheaply, while OmniRoute handles each streaming chunk more cheaply.

Throughput Under Load

Both gateways hit their ceiling at just ten concurrent clients; beyond that, only the queue grows. LiteLLM with one worker process sustains 71 standard requests per second versus 36 for OmniRoute with rate-limit protection disabled, but falls behind on streaming, 20 versus 25.

With a second worker process, LiteLLM overtakes OmniRoute in both modes. The gateway was allocated two cores; the OmniRoute server is roughly 1.5 times slower, and the hardware correction is described in the section on testing limitations.

The two halves of the chart have different scales, up to 140 requests per second on the left and up to 50 on the right, so lines at the same height represent different numbers. A streaming response costs the gateway more than a standard one, because instead of a single response it has to pass through fifty separate chunks. This is much more noticeable for LiteLLM with one process: it passes 3.5 times fewer streaming requests than standard ones, 20 versus 71, whereas for OmniRoute the gap is only 1.4 times, 25 versus 36. When LiteLLM runs with two worker processes, its ceiling rises to 130 standard and 38.5 streaming requests per second, nearly doubling in each mode. So on standard responses LiteLLM pulls far ahead, and on streaming it catches up with OmniRoute even after the hardware correction.

Once a gateway is running at its limit, each new client simply lengthens the queue, and latency can be estimated in advance by dividing the number of clients by the throughput. LiteLLM with one process passes about 18 streaming requests per second, so with 200 clients each one would wait about 11 seconds (200/18). In our test, half of the requests did indeed take longer than 10.6 seconds. By the same logic, OmniRoute comes out at about 9 seconds against a measured 8.5, and LiteLLM with two processes at about 6 seconds against a measured 5.8.

The gateways differ most on the slowest requests. Taking standard responses and looking at the 1% of requests that waited longest, OmniRoute took 30 and 35 seconds for them at 100 and 200 clients. For LiteLLM with one process, the same slowest requests took 4.5 seconds at 100 clients and 13.6 seconds at 200. It appears OmniRoute serves its queue less evenly, so some requests wait much longer than others.

Without rate-limit protection there were almost no errors. The only exception was LiteLLM with two processes at 200 clients, where 2 out of 3,420 requests had their connection dropped, or 0.06%.

One Worker Process Uses One Core

Docker reports CPU usage so that 100% corresponds to one fully busy core; with two cores allocated, the limit is 200%. Under load, both gateways on default settings stayed around 100%, meaning they ran on one core while the second sat idle. The maximum throughput of single-process LiteLLM and of OmniRoute from the previous section therefore reflects what one core can do, and only LiteLLM with two processes used both cores, reaching 205%.

Peak under load

LiteLLM, 1 process

LiteLLM, 2 processes

OmniRoute

Gateway CPU, median and peak (%)

102 and 116

110 and 205

106 and 154

Gateway memory at start and at peak (MB)

672 and 910

1,713 and 2,104

489 and 1,154

Storage, peak memory (MB)

Postgres, 200

Postgres, 351

Redis, 9

Storage, peak CPU (%)

41

95

14

In its Docker image, LiteLLM starts as a single Python process by default. With the --num_workers 2 flag the gateway launches a second process, and throughput nearly doubles, from 71 to 130 standard requests per second. Each process keeps its own copy of the gateway in memory, so consumption rose from 0.9 to 2.1 GB. In the agentgateway test, LiteLLM with 18 processes used about 12 GB, or roughly 0.7 GB per process.

In addition, LiteLLM writes a row to the spend log for every request, so Postgres is loaded along with the gateway. With two processes, the database used almost a full core at peak, which is a lot on a four-core server. This load should be taken into account when choosing the number of processes; it may be worth moving the database to a separate server.

OmniRoute processes requests in a single Node.js thread; CPU usage above 100%, up to 154%, comes from the runtime’s background threads. We found no equivalent of --num_workers in OmniRoute, so scaling it will apparently require multiple instances behind a load balancer. We did not test that setup.

Rate-Limit Protection in OmniRoute

Gateways have their quirks. The first OmniRoute run on the test machine produced one request per second: each single request took 350 milliseconds to pass through the gateway, while the model mock behind it responded in two. The container’s CPU was idle, so the delay was being introduced by the gateway itself. The cause was not obvious at first: the OmniRoute dashboard is far from minimalist, and the inconspicuous “Protected” badge made troubleshooting considerably harder.

On default settings, OmniRoute let through about one request per second, kept requests queued for up to 74 seconds, and at 100 and 200 concurrent clients started responding with 502, 503, and 429 errors.

Load

Standard responses

Streaming output

1 client

1 request per second, median 350 milliseconds

2.9 requests per second, median 350 milliseconds

10 clients

1 request per second, 95th percentile 39.8 seconds

1 request per second, 95th percentile 42.8 seconds

50 clients

1.3 requests per second, median 51.5 seconds

1.3 requests per second, median 51.7 seconds

100 clients

0.7 requests per second, 40% 502 errors

1.5 requests per second, 95th percentile 66.8 seconds

200 clients

all requests failed with 503 and 429 errors

3 requests per second, 95th percentile 73.4 seconds

The 350 milliseconds per single request suggested a deliberate pause, because the delays were identical. Half of the single requests completed in under 350 milliseconds and 95% in under 358.2, so the spread was almost zero. With a gateway that is simply slow to process requests, timing varies noticeably from one request to the next. CPU usage confirmed this: during the run the OmniRoute container used about 20% of one core and spent most of the time just waiting.

The pauses are added by rate-limit protection. In the dashboard it is marked with a “Protected” badge, and it is enabled automatically for all providers with an API key, including our mock.

The mock connection in the OmniRoute dashboard, with the “Protected” badge in the middle of the row.

The toggle in the connection settings does not turn protection off; to do that, you have to disable it for the entire gateway with the environment variable RATE_LIMIT_AUTO_ENABLE=false:

omniroute:
    environment:
      - RATE_LIMIT_AUTO_ENABLE=false

After restarting the container, a single request took 31.5 milliseconds instead of 350, the errors disappeared, and all the other OmniRoute figures in this article were taken with this setting. OmniRoute was built primarily for working with free tiers, where accounts get banned for sending requests too often, and there the protection is useful. If the gateway fronts your own self-hosted model or a paid API, it makes sense to turn it off.

Testing Limitations

The gateways ran on different servers, and the OmniRoute server turned out to be roughly 1.5 times slower. We calculated the hardware correction from the baseline measurements: 1.45x for streaming responses and 1.56x for standard ones. This brings one more limitation: the baseline involved only the client and mock written in Python, whereas OmniRoute runs on Node.js, so it is hard to say how accurately the correction carries over to a different runtime.

The load was synthetic, with a 200-word request, a 50-token response, and a single mock instead of a real model. Failover to fallback models, retries, caching, OmniRoute’s model chains, and LiteLLM’s router were not covered by the test.

Conclusion: Which Gateway to Choose

In terms of speed, LiteLLM with two worker processes beats OmniRoute in both modes, but in many situations a difference of 20–70 requests per second per core matters less than what the gateway can do and what job it was designed for.

Task

What to choose

Why

A company needs to track how much each department spends on LLMs

LiteLLM

LiteLLM records spending for each key in Postgres on its own, and the gateway handles more standard requests than OmniRoute

Many short requests without streaming, such as classification or data extraction

LiteLLM with --num_workers equal to the number of cores

130 requests per second on two cores

A coding agent with long streaming responses on a server with one core for the gateway

OmniRoute

In our single-core test, OmniRoute passed more streaming requests, 25 versus 20 for LiteLLM

Free tiers and subscriptions from different providers

OmniRoute

The gateway was built specifically for this kind of work

Your own vLLM, Ollama, or a paid API behind OmniRoute

OmniRoute with RATE_LIMIT_AUTO_ENABLE=false

Otherwise you get about one request per second and 429 and 503 errors under load

With LiteLLM, the first thing to check after installation is the number of worker processes, since out of the box the gateway uses one core no matter how many the container is given. It is also worth keeping the Postgres load in mind. With OmniRoute, the more important decision is what to do with rate-limit protection: for a self-hosted model, it is better to turn it off.

Pre-installed LiteLLM and OmniRoute
Order a server with LiteLLM or OmniRoute pre-installed and connect your models immediately after launch.

Other articles

30.10.2026

OpenWebUI Pipes: Why Write Code When "Everything Is Already in the Settings"?

Configuring a custom model with tools and RAG in OpenWebUI is easy. Making it behave predictably in production is the hard part. Our support bot powered by Gemma 4 initially provided plausible answers, but they lacked actual system data. We analyzed why this happens and transformed a "single model in a UI" into a deterministic pipeline using Pipes.

20.10.2026

GPU VPS vs GPU Dedicated Servers: Which to Choose?

The same RTX 4090 with a €150 price gap: what are you really paying for? Learn how to tell a whole GPU from a slice of one, when a GPU VPS is enough, and when it is time to move to a dedicated GPU server.

20.10.2026

How to Run Language Models (DeepSeek, Gemma, Phi) on Your Own Server: A Complete 2026 Guide

Step-by-step guide to running DeepSeek, Gemma, and Phi on your own server. Ollama, vLLM, Docker, GPU configuration, and code examples.

22.09.2026

Ways to Install an Application on a Server and How They Differ

The debate over how to install software on a server usually ends in a stalemate because everyone has their own habits. We categorized twelve methods, ran five of them on identical servers with a stopwatch, and discovered that more than half of the time difference is not spent installing the application itself, but installing the tool itself.

16.09.2026

How to Check Disk Space Usage in Linux

Your disk reports free space, and the server still refuses to write a file — that is inodes, not gigabytes, and df -h will never show it. The full diagnostic path from df and du to ncdu, find and lsof +L1, plus what is safe to delete and how to keep the disk from filling up again.

Upload