Skip to main content

The hidden cost of --reload in uvicorn: what actually consumes CPU in production

Rogelio Guerra Riverón
Author
Rogelio Guerra Riverón
Building my own web infrastructure from scratch. Here I document each step: servers, networks, containers and everything that comes along.

The Problem Nobody Sees
#

Two months ago I deployed a FastAPI API to production and the server was behaving strangely. CPU stable at 40-50% for no apparent reason. I thought it was a memory leak, that it was the logs, that it was the database. It was --reload.

It turns out that copy-pasting the development command directly into the Docker container is more common than it should be. And yes, uvicorn with --reload works. The server responds. Requests go fast. But there’s a cost you don’t see until you have 10K requests daily.

What exactly is the file-watcher
#

The --reload flag in uvicorn starts an additional process that monitors all Python files in your project. Not just your code. All of them.

When you activate --reload, uvicorn:

  1. Starts a process manager (watchfiles by default)
  2. Every X seconds (default 0.4s) scans all .py files in the directory
  3. Calculates checksums or hashes of each file
  4. If it detects changes, restarts the complete worker
  5. Meanwhile, keeps scanning on every cycle, even without changes

This scanning isn’t free. In a medium-sized project with 200 Python files distributed across vendor, libraries, and your own modules, each watchfiles cycle touches disk and CPU.

How it consumes CPU on each request
#

The criminal part is that the file-watcher doesn’t pause during requests. While your API is processing a request:

  • The monitor keeps scanning files in the background
  • Competes for disk I/O with your application
  • In containers, if you don’t have resource limits, it can consume more CPU than the request logic itself

I measured this on my server. With a simple request to an endpoint that takes 50ms:

Without --reload:

CPU: 2-3% por request
I/O wait: <1%

With --reload:

CPU: 8-12% por request
I/O wait: 3-5%

It doesn’t look like much in an isolated request. But with 100 concurrent requests, that overhead multiplies.

How to detect it on your server
#

1. Look at running processes
#

ps aux | grep uvicorn

If you see two uvicorn processes (or uvicorn + watchfiles), you have --reload active.

2. Check your startup command
#

# MAL - esto es lo que probablemente tienes
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

# BIEN - así debe estar en producción
uvicorn main:app --host 0.0.0.0 --port 8000

3. Monitor CPU during a load test
#

# Terminal 1: corre tu servidor
docker run -it tu-contenedor

# Terminal 2: genera carga
ab -n 1000 -c 10 http://localhost:8000/endpoint

Watch top or docker stats. If you see unexplained spikes, suspect --reload.

4. Check uvicorn logs
#

With --reload active, you’ll see messages like:

INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO:     Will watch for changes in these directories: ...

If you see “Will watch for changes”, you have a problem.

The solution (it’s obvious, but important)
#

In Docker, make sure your Dockerfile does NOT use --reload:

FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

# Aquí no va --reload
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]

For local development, use --reload without guilt:

uvicorn main:app --reload

What I learned
#

The file-watcher in uvicorn is excellent for development. It’s transparent, works well, and speeds up your cycle. But in production it’s like leaving your computer continuously scanning with antivirus.

I reviewed my other containers after this. I found three more with --reload active. After removing it, CPU consumption dropped between 30-45%.

It’s one of those bugs that isn’t a bug. Your application works. Requests are processed. But your server is doing invisible work it doesn’t need to do.


Next time before deploying to production, grep for --reload. It will save you a troubleshooting session.


Recommended Equipment#

Affiliate links. No extra cost for you.