What is uvicorn.run()?
uvicorn.run() is the programmatic interface to Uvicorn, Python's lightning-fast ASGI web server. Unlike the command-line interface, it allows you to start and configure your server directly from Python code, giving you complete control over server lifecycle and configuration.
Perfect for production deployments, testing environments, and applications that need dynamic server configuration, uvicorn.run() is the go-to choice for modern Python web applications built with FastAPI, Starlette, and other ASGI frameworks.
Requirements: Python 3.10+ (as of uvicorn 0.40.0). Python 3.14 is supported since uvicorn 0.38.0. For optimal performance, install with pip install uvicorn[standard] which includes uvloop and httptools. The latest version is 0.41.0 (February 2026).
Quick Start
Get up and running with uvicorn.run() in seconds:
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def read_root():
return {"message": "Hello, World!"}
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
That's it! Your ASGI application is now running with automatic reloading enabled for development.
Parameters Reference
Configure every aspect of your server with these comprehensive parameters:
Application
app
str | ASGI AppYour ASGI application. Can be a string in "module:attribute" format or the application object directly.
factory
boolTreat app as an application factory (a callable that returns an ASGI app). Default: False
app_dir
strDirectory to add to sys.path when looking for the application module. Default: current working directory
Socket Binding
host
strBind socket to this host. Use "0.0.0.0" to make the server available externally. Default: "127.0.0.1"
port
intBind socket to this port. Use 0 to bind to an available port. Default: 8000
uds
strBind to a UNIX domain socket instead of TCP. Useful for reverse proxy setups.
fd
intBind to socket from this file descriptor. Useful for socket activation.
Development
reload
boolEnable auto-reload for development. Watches for file changes and restarts the server. Default: False
reload_dirs
list[str]Directories to watch for file changes when reload is enabled.
reload_delay
floatDelay in seconds between detecting a change and reloading. Default: 0.25
reload_includes
list[str]Glob patterns for files to include in reload watching. Requires watchfiles.
reload_excludes
list[str]Glob patterns for files to exclude from reload watching. Requires watchfiles.
Production
workers
intNumber of worker processes. Reads from $WEB_CONCURRENCY env var if set. Cannot be used with reload. Default: 1
env_file
strPath to environment configuration file to load.
timeout_worker_healthcheck
intTimeout in seconds for worker health check. Default: 5
Logging
log_level
strLogging level: "critical", "error", "warning", "info", "debug", "trace". Default: "info"
log_config
str | dictLogging configuration file path (.json or .yaml) or a dictionary config.
access_log
boolEnable or disable access logging. Default: True
use_colors
boolEnable or disable colorized log formatting. Default: auto-detected
Protocol Implementation
loop
strEvent loop implementation: "auto", "asyncio", "uvloop". Default: "auto"
http
strHTTP protocol implementation: "auto", "h11", "httptools". Default: "auto"
ws
strWebSocket protocol implementation: "auto", "none", "websockets", "websockets-sansio", "wsproto". Default: "auto"
lifespan
strLifespan protocol implementation: "auto", "on", "off". Default: "auto"
interface
strApplication interface type: "auto", "asgi3", "asgi2", "wsgi". Default: "auto"
h11_max_incomplete_event_size
intMaximum size of incomplete HTTP events buffer (h11 only). Default: 16384
WebSocket Settings
ws_max_size
intMaximum WebSocket message size in bytes. Default: 16777216 (16MB)
ws_max_queue
intMaximum WebSocket receive queue length. Default: 32
ws_ping_interval
floatWebSocket ping interval in seconds. Default: 20.0
ws_ping_timeout
floatWebSocket ping timeout in seconds. Default: 20.0
ws_per_message_deflate
boolEnable WebSocket per-message compression. Default: True
HTTP Settings
root_path
strSet the ASGI root_path for applications mounted at a subpath. Default: ""
proxy_headers
boolEnable X-Forwarded-Proto, X-Forwarded-For headers. Default: True
forwarded_allow_ips
str | listComma-separated list of trusted proxy IPs. Default: "127.0.0.1"
server_header
boolInclude "Server" header in responses. Default: True
date_header
boolInclude "Date" header in responses. Default: True
headers
list[tuple]Custom HTTP headers to add to all responses.
HTTPS / SSL
ssl_keyfile
strPath to SSL key file for HTTPS support.
ssl_certfile
strPath to SSL certificate file for HTTPS support.
ssl_keyfile_password
strPassword to decrypt the SSL key file if encrypted.
ssl_version
intSSL protocol version to use. Default: ssl.PROTOCOL_TLS_SERVER
ssl_cert_reqs
intWhether client certificates are required. Default: ssl.CERT_NONE
ssl_ca_certs
strPath to CA certificates file for client certificate verification.
ssl_ciphers
strSSL ciphers to use. Default: "TLSv1"
Resource Limits
limit_concurrency
intMaximum number of concurrent connections to allow before rejecting new connections.
limit_max_requests
intMaximum number of requests per worker before terminating and respawning.
limit_max_requests_jitter
intJitter to add to limit_max_requests to stagger worker restarts and avoid all workers restarting simultaneously. Default: 0
backlog
intMaximum number of pending connections in the connection backlog. Default: 2048
Timeouts
timeout_keep_alive
intTimeout in seconds for keep-alive connections. Default: 5
timeout_graceful_shutdown
intTimeout in seconds for graceful shutdown. After this time, connections are forcefully closed.
Real-World Examples
Production Configuration
import uvicorn
import os
if __name__ == "__main__":
uvicorn.run(
"app.main:app",
host="0.0.0.0",
port=int(os.getenv("PORT", 8000)),
workers=int(os.getenv("WEB_CONCURRENCY", 4)),
log_level="warning",
access_log=False,
proxy_headers=True,
forwarded_allow_ips=os.getenv("TRUSTED_PROXIES", "127.0.0.1"),
limit_max_requests=10000, # Recycle workers to prevent memory leaks
limit_max_requests_jitter=1000, # Stagger worker restarts
timeout_graceful_shutdown=30,
ssl_keyfile="./ssl/key.pem",
ssl_certfile="./ssl/cert.pem"
)
Development with Auto-Reload
import uvicorn
if __name__ == "__main__":
uvicorn.run(
"app.main:app",
host="127.0.0.1",
port=8000,
reload=True,
reload_dirs=["./app"],
reload_includes=["*.py", "*.html"],
log_level="debug"
)
Advanced Configuration with Config Object
import uvicorn
from uvicorn.config import Config
from uvicorn.server import Server
async def run_server():
config = Config(
"app.main:app",
host="0.0.0.0",
port=8000,
log_level="info",
access_log=True,
use_colors=True
)
server = Server(config)
await server.serve()
if __name__ == "__main__":
import asyncio
asyncio.run(run_server())
Factory Mode (Application Factory)
import uvicorn
# In app/main.py:
# def create_app():
# app = FastAPI()
# # Configure app with dependencies
# return app
if __name__ == "__main__":
uvicorn.run(
"app.main:create_app",
factory=True, # Treat as factory function
host="0.0.0.0",
port=8000,
reload=True
)
UNIX Domain Socket (for Reverse Proxy)
import uvicorn
if __name__ == "__main__":
uvicorn.run(
"app.main:app",
uds="/tmp/uvicorn.sock", # UNIX socket instead of TCP
workers=4,
log_level="warning",
proxy_headers=True,
forwarded_allow_ips="*" # Trust all (configure nginx properly)
)
Testing Environment
import uvicorn
import threading
import time
def start_test_server():
uvicorn.run(
"tests.app:app",
host="127.0.0.1",
port=8001,
log_level="critical",
access_log=False
)
# Start server in background for testing
server_thread = threading.Thread(target=start_test_server, daemon=True)
server_thread.start()
time.sleep(1) # Wait for server to start
# Run your tests here
Best Practices
Performance & Security
- Install with pip install uvicorn[standard] for uvloop and httptools performance boost
- Use multiple workers in production for CPU-bound tasks (or use Gunicorn as process manager)
- Disable access logs in production for better performance (access_log=False)
- Use environment variables for configuration via env_file parameter
- Enable SSL/TLS for production deployments with proper certificates
- Set appropriate log levels for different environments ("warning" for production)
- Use reload only in development environments (never in production)
- Configure forwarded_allow_ips carefully when behind a proxy - only trust known proxies
- Set limit_max_requests to recycle workers and prevent memory leaks, and use limit_max_requests_jitter to stagger restarts
- Configure timeout_graceful_shutdown for clean shutdown handling
Development Tips
- Use reload_dirs to watch specific directories for changes
- Set debug log level during development (log_level="debug")
- Use different ports for different services
- Keep development and production configs separate
- Use reload_includes/reload_excludes for fine-grained reload control (requires watchfiles)
- Use factory mode (factory=True) for apps that need fresh instances on reload
Deployment Options
- Use uvicorn's built-in workers option for simple multi-process deployment
- For production, consider using Gunicorn with the uvicorn-worker package: gunicorn -k uvicorn_worker.UvicornWorker
- Place behind a reverse proxy (nginx) for SSL termination, load balancing, and static files
- Use UNIX domain sockets (uds) for reverse proxy communication to avoid TCP overhead
Deprecation Notices
Be aware of these deprecations when upgrading uvicorn:
uvicorn.workers module deprecated
The uvicorn.workers module is deprecated and will be removed in a future release. If you're using Gunicorn with uvicorn workers, migrate to the separate uvicorn-worker package:
pip install uvicorn-worker
Then use: gunicorn -k uvicorn_worker.UvicornWorker
Python 3.9 no longer supported
As of uvicorn 0.40.0 (December 2025), Python 3.9 support has been dropped. Upgrade to Python 3.10 or later.
ServerState deprecated from main module
As of uvicorn 0.34.1 (April 2025), importing ServerState from the main uvicorn module is deprecated. Import it from uvicorn.server instead.
Common Patterns
Environment-Based Configuration
import uvicorn
import os
def get_config():
if os.getenv("ENVIRONMENT") == "production":
return {
"host": "0.0.0.0",
"port": int(os.getenv("PORT", 8000)),
"workers": int(os.getenv("WORKERS", 4)),
"log_level": "warning",
"access_log": False
}
else:
return {
"host": "127.0.0.1",
"port": 8000,
"reload": True,
"log_level": "debug"
}
if __name__ == "__main__":
config = get_config()
uvicorn.run("app.main:app", **config)
Graceful Shutdown
import uvicorn
import signal
import asyncio
class GracefulServer:
def __init__(self):
self.server = None
self.should_exit = False
async def run(self):
config = uvicorn.Config("app.main:app", host="0.0.0.0", port=8000)
self.server = uvicorn.Server(config)
# Setup signal handlers
for sig in (signal.SIGTERM, signal.SIGINT):
signal.signal(sig, self.signal_handler)
await self.server.serve()
def signal_handler(self, signum, frame):
print(f"Received signal {signum}")
self.should_exit = True
if self.server:
self.server.should_exit = True
if __name__ == "__main__":
server = GracefulServer()
asyncio.run(server.run())