Python Uvicorn FastAPI Host Port Reload and Workers
python uvicorn fastapi host port reload and workers: Learn how to set host, port, reload, and workers when running FastAPI with Uvicorn, and when to use each option in...
python uvicorn fastapi host port reload and workers requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
When you run a FastAPI application, Uvicorn is the ASGI server that serves it. The command line options --host, --port, --reload, and --workers control where the server listens, whether it restarts on code changes, and how many processes handle requests. Getting these right matters because the same command that works on your laptop can cause problems in production if you bind to the wrong interface or enable reload alongside multiple workers.
Running Uvicorn from the Command Line
The most direct way to start a FastAPI app with Uvicorn is through the uvicorn command. Given a module main.py containing an app instance named app, the default command is:
uvicorn main:app
This binds to 127.0.0.1 on port 8000 with a single worker process and no reload. To change the host and port, pass explicit options:
uvicorn main:app --host 0.0.0.0 --port 8080
To enable automatic restart when source files change, add --reload:
uvicorn main:app --reload
To run multiple worker processes, use --workers:
uvicorn main:app --workers 4
These options are independent, but --reload and --workers cannot be used together. Uvicorn raises an error if you try. The reason is that reload uses a separate watch process to monitor files, and that process does not participate in the worker pool. Combining them would require each worker to also watch files, which defeats the purpose of process isolation.
Setting Host and Port
The host determines which network interface Uvicorn listens on. The default 127.0.0.1 only accepts connections from the same machine. That is fine for local development, but if you run the server inside a container or on a remote server, you need 0.0.0.0 to accept connections from outside.
uvicorn main:app --host 0.0.0.0
Binding to 0.0.0.0 does not mean the server is publicly exposed; it means it listens on all available network interfaces. The actual exposure depends on your firewall and network configuration. For a local test, 127.0.0.1 is usually sufficient. For a development container that needs to be reachable from the host machine, 0.0.0.0 is required.
The port can be any valid TCP port. Port 8000 is the default, but you can choose another if that port is already in use. When you run multiple Uvicorn instances on the same machine, each must use a different port.
Using Reload for Development
--reload makes Uvicorn watch your Python files and restart the server whenever a file changes. This is a development convenience that saves you from manually restarting the process after every edit.
uvicorn main:app --reload
Uvicorn implements reload by running a separate watch process that monitors the file system. When a change is detected, it kills the worker process and starts a new one. This means your application state is lost on every reload, which is expected during development.
Reload works best when you are iterating on code locally. It is not intended for production because:
- It adds overhead from file watching.
- It restarts the server unexpectedly if a file is touched.
- It does not provide the same isolation as multiple workers.
The reload process also watches the directory where the application is imported from. If you have large directories or generated files, you can use --reload-dir to limit the watch scope.
Using Workers for Production
--workers tells Uvicorn to start multiple worker processes, each running a separate instance of your application. This allows the server to handle more concurrent requests because each worker has its own event loop and can process requests independently.
uvicorn main:app --workers 4
Workers are useful when your application is CPU-bound or when you want to utilize multiple CPU cores. They are also beneficial when you run behind a reverse proxy that distributes incoming connections across the workers.
The number of workers you choose depends on your workload and available resources. A common starting point is one worker per CPU core, but you should measure your application's behavior under load. Each worker consumes memory because it loads your application and its dependencies. Too many workers can exhaust memory or cause excessive context switching.
When you use workers, Uvicorn acts as a master process that manages the worker processes. It does not perform load balancing itself; the operating system handles connection distribution. If a worker crashes, the master process restarts it, which provides a basic level of fault tolerance.
Configuring Uvicorn Programmatically
Instead of using the command line, you can start Uvicorn from within Python using uvicorn.run(). This is useful when you need to pass configuration dynamically or when you want to embed the server startup in a script.
import uvicorn if __name__ == "__main__": uvicorn.run( "main:app", host="0.0.0.0", port=8080, reload=True, workers=1 )
The reload and workers parameters follow the same rules as the command line: they are mutually exclusive. If you set both, Uvicorn raises an error.
When you pass a string like "main:app", Uvicorn imports the module and locates the app. You can also pass the app object directly:
import uvicorn from main import app if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8080)
Passing the app object directly is convenient in a single-file script, but it can cause issues with reload because the reload process needs to re-import the module. Using the string form is safer when reload=True.
Why Reload and Workers Are Mutually Exclusive
The conflict between --reload and --workers is not arbitrary. Reload relies on a single watch process that restarts the entire server. If you have multiple workers, each worker would need to be restarted individually, and the watch process would have to coordinate that. Uvicorn does not implement this because it would complicate the process model and provide little benefit.
In production, you typically want multiple workers and no reload. In development, you want reload and a single worker. If you need both, you can run a separate process for reload and a separate set of workers, but that is rarely useful.
Common Pitfalls and Runtime Behavior
One frequent mistake is trying to use --reload with --workers and seeing an error like:
Error: --reload and --workers cannot be used together
This is intentional. If you need to test multiple workers locally, run without reload and manually restart after changes.
Another pitfall is binding to 127.0.0.1 when you need to access the server from another machine. If you run Uvicorn in a Docker container with --host 127.0.0.1, the container will not accept connections from the host because the loopback interface inside the container is separate. Use --host 0.0.0.0 in that case.
When you increase the number of workers, each worker gets its own copy of the application. If your application uses in-memory state or a database connection pool, each worker will have its own instance. This can lead to unexpected behavior if you assume shared state across requests. Use an external store like Redis or a database for shared data.
Production Considerations
In production, you rarely run Uvicorn directly as the public-facing server. Typically, you place it behind a reverse proxy like Nginx or a load balancer. The proxy handles TLS termination, request routing, and static file serving. Uvicorn then focuses on serving your FastAPI application.
When you run multiple workers, you need to ensure that the reverse proxy distributes connections evenly. Most proxies support keep-alive connections, which can cause requests to stick to a single worker. That is usually fine, but if you need true load balancing, you may need to adjust proxy settings.
The number of workers should be based on your application's concurrency model. FastAPI is asynchronous, so a single worker can handle many concurrent I/O-bound requests. If your workload is I/O-bound, a few workers may be enough. If you have CPU-bound operations, you need more workers to utilize multiple cores.
Memory usage is also a factor. Each worker loads your application, including all imported modules and dependencies. If your application is large, each worker can consume hundreds of megabytes. Monitor memory usage and adjust the worker count accordingly.
Finally, consider using a process manager like Gunicorn with Uvicorn workers for production. Gunicorn can manage worker lifecycle, handle graceful shutdowns, and provide more configuration options. The command would look like:
gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app
This combines Gunicorn's process management with Uvicorn's ASGI support. It is a common production setup for FastAPI applications.