Production Configuration

Multiple workers, quieter logs, trusted proxies and worker recycling. Behind a reverse proxy that terminates TLS, drop the ssl_* arguments.

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

With reload=True, the app must be passed as an import string so the reloader can import it again. Install watchfiles (included in uvicorn[standard]) to use reload_includes and reload_excludes.

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"
    )

Config and Server Objects

uvicorn.run() is a thin wrapper around Config and Server. Use them directly to start the server inside an existing event loop.

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)

With factory=True, uvicorn calls the function to build the app, in each worker and after each reload.

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
    )

Environment-Based Configuration

Keep one entry point and switch settings with an environment variable.

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)

Testing Environment

Start a real server in a background thread for end-to-end tests.

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

More Examples