Blog Post

Using Uvicorn in Python: From Local to Production

Learn how to use Uvicorn in Python: what it is, how to install it, run ASGI and FastAPI apps, and deploy with Gunicorn for a production-ready API stack.

Aug 7, 202615 min read
uvcorn in pythonUvicorn in Python: A Practical Setup Guide
Using Uvicorn in Python: From Local to Production

Setting up Uvicorn in Python often feels like extra plumbing when you just want your API online. Many people even search for uvcorn in python and still end up stuck between docs and GitHub issues. Uvicorn is an ASGI web server that runs modern async Python apps, and with a small set of commands you can get from import to production-ready. This guide walks through what Uvicorn is, how to install it, how to run both raw ASGI and FastAPI apps, and how to put it behind Gunicorn in production. Along the way, it highlights a few practical choices that matter for SaaS teams under real delivery pressure.

For context, Ahmed Hasnain is a product-minded full-stack developer who works with Python, Laravel, React, Vue, and Next.js on real SaaS backends. If you want a clear mental model and copy‑pasteable commands rather than another theory lesson, keep reading.

Now let us pull the pieces together step by step so your next Python service starts clean and stays predictable in production.

Key Takeaways

Key takeaways from this Uvicorn setup guide help you decide how to run your next Python API without guesswork. Read these first, then skim the sections that match your current stage.

  • Uvicorn is the default ASGI server for async Python frameworks like FastAPI, Starlette, and Django Channels, which means most modern Python API tutorials and templates already expect it. Using it keeps your stack close to community standards and makes hiring and onboarding easier.

  • Installing Uvicorn with the standard extras gives you uvloop, httptools, websockets, watchfiles, and other helpers that speed up I/O, improve HTTP parsing, and restart the server on code changes. Pick minimal installs only for very small tools or extremely constrained environments.

  • For local work, use commands like uvicorn main:app with the reload flag and, for production, either Uvicorn’s workers or Gunicorn with the uvicorn-worker package. Uvicorn also has a Python API so you can start it inside scripts or existing asyncio programs when you need more control.

Tip: Read through the install and run sections with your own project open so you can adapt the commands on the spot rather than trying to memorize them.

What Is Uvicorn And Why Does It Matter?

Visual comparison of ASGI async flow versus WSGI sync flow

Uvicorn is an asynchronous web server that runs ASGI Python applications such as FastAPI or Starlette. It matters because Uvicorn solves the scaling and real‑time limits of older WSGI servers when you build modern APIs and dashboards. At its core, it listens for HTTP and WebSocket connections, parses requests, and hands them to your ASGI app while an event loop keeps many requests in flight without blocking.

Older stacks based on WSGI, such as Django with Gunicorn or Flask with uWSGI, use a synchronous model. Each worker handles one request at a time and waits while that code talks to PostgreSQL, Redis, Stripe, or a third‑party API. For chat apps, live dashboards, or webhook‑heavy SaaS products, that model wastes a lot of server time. With Uvicorn plus ASGI, a single process can juggle many open connections, which is why FastAPI benchmarks usually look so good. That mix of concurrency and simplicity is what makes Uvicorn attractive to small startup teams as well as large Python shops.

To make this concrete, consider a notification service that:

  • Receives thousands of webhooks per minute
  • Pushes updates to browser dashboards over WebSockets
  • Talks to external APIs for billing and analytics

On a synchronous stack, you would need many more workers to keep up. With Uvicorn and ASGI, a smaller pool of async workers can keep connections open while they wait on I/O without blocking new requests.

How Does ASGI Differ From WSGI?

ASGI differs from WSGI by using an async callable with a richer event model instead of a single synchronous function. In ASGI, your application receives scope, receive, and send objects and can await multiple messages for a single connection. This lets a FastAPI or Starlette app keep WebSocket chats, server‑sent events, and long‑polling HTTP all running without tying up one worker per client.

WSGI, which powers classic Flask and many Django deployments, expects a plain callable that takes a request and returns a response once. That design works for simple forms and CRUD pages but it has trouble with websockets, streaming, and high I/O concurrency. For real‑time dashboards, notification systems, or marketing platforms that process a large number of webhooks, ASGI plus Uvicorn is almost always the better choice.

From a practical angle:

  • Reach for WSGI when:

    • You maintain an existing Django or Flask app with simple request/response flows
    • You do not need WebSockets or high concurrency
  • Prefer ASGI and Uvicorn when:

    • You build new APIs with FastAPI or Starlette
    • You expect streaming responses or long‑lived connections
    • You care about efficient use of a few CPU cores on small servers

How Do You Install Uvicorn In Python?

Programmer installing Uvicorn package in terminal

You install Uvicorn from PyPI using pip or a newer tool like uv, and you pick between a minimal or standard install. The standard option adds C‑backed extras that give better performance and developer experience for most teams. On a typical project, you can add Uvicorn to your virtual environment with one command and be ready to serve a FastAPI app within minutes.

Before installing, it helps to:

  • Create a dedicated virtual environment
  • Decide whether this will be a tiny internal tool or a real production service
  • Check that your Python version is 3.10 or newer

For a minimal install that keeps dependencies light, run:

pip install uvicorn

For most real projects, prefer the standard extras:

pip install "uvicorn[standard]"

If you are using Astral’s uv tool instead of pip, you can run:

uv add uvicorn

The extras behind that standard bracket matter. Packages like uvloop and httptools speed up the asyncio event loop and HTTP parsing. websockets handles WebSocket protocol details, watchfiles powers the reload flag in development, python-dotenv loads .env files, and PyYAML lets you drive logging from a YAML config. Uvicorn itself runs on Python 3.10 or newer and is released under the BSD‑3‑Clause license, which fits most commercial SaaS products.

Tip: Pin your Uvicorn version in requirements.txt or pyproject.toml so you do not get surprise behavior changes during deploys.

What's The Difference Between Minimal And Standard Installs?

The difference between minimal and standard installs comes down to extra features and speed. The core package gives you the server, but the extras give you a nicer day‑to‑day workflow and better throughput.

AspectMinimal InstallStandard Install
Core packagesclick, h11, typing-extensionsSame core packages
Performance helpersPure Python onlyAdds uvloop, httptools, websockets
Developer comfortNo reload or env file helpersAdds watchfiles, python-dotenv, PyYAML
Typical useTiny tools, experimentsMost dev and production services

For a startup building a FastAPI API that will see real traffic, pick the standard install and treat the minimal one as a special case. The extra dependencies are stable, widely used in the Python world, and usually worth the modest overhead.

A simple rule of thumb:

  • Use minimal for:

    • Throwaway scripts
    • Learning projects
    • Very locked‑down environments
  • Use standard for:

    • Any API that other teams depend on
    • Customer‑facing products
    • Services you expect to monitor and scale over time

How Do You Run A Python App With Uvicorn?

Running a Python app with Uvicorn means pointing the server at an ASGI callable, either from a framework like FastAPI or a raw async function. You can do this from the command line or from Python code depending on your deployment model. Once you see the module and object naming pattern, switching between simple demos and production entrypoints feels natural.

At a high level, the process is:

  1. Write or expose an ASGI app object
  2. Install Uvicorn (with or without extras)
  3. Run uvicorn modulename:appname with the right flags

Building A Minimal ASGI App

A minimal ASGI app helps you see what Uvicorn expects before a framework wraps it. You define an async function that accepts scope, receive, and send, then send back a simple HTTP response.

# main.py
async def app(scope, receive, send):
    assert scope["type"] == "http"
<span class="k">await</span> <span class="n">send</span><span class="p">({</span>
    <span class="s2">"type"</span><span class="p">:</span> <span class="s2">"http.response.start"</span><span class="p">,</span>
    <span class="s2">"status"</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
    <span class="s2">"headers"</span><span class="p">:</span> <span class="p">[</span>
        <span class="p">(</span><span class="sa">b</span><span class="s2">"content-type"</span><span class="p">,</span> <span class="sa">b</span><span class="s2">"text/plain"</span><span class="p">),</span>
    <span class="p">],</span>
<span class="p">})</span>
<span class="k">await</span> <span class="n">send</span><span class="p">({</span>
    <span class="s2">"type"</span><span class="p">:</span> <span class="s2">"http.response.body"</span><span class="p">,</span>
    <span class="s2">"body"</span><span class="p">:</span> <span class="sa">b</span><span class="s2">"Hello, world!"</span><span class="p">,</span>
<span class="p">})</span>

Start it with:

uvicorn main:app

Here main matches the filename main.py and app is the callable you defined. That module plus attribute pattern is the same one you will use with FastAPI, Starlette, or Django Channels.

Once the server starts, you should see log output that includes:

  • The host and port (default 127.0.0.1:8000)
  • The reload status (off by default)
  • A line that says “Application startup complete”

Then you can open http://127.0.0.1:8000/ in a browser or call it with curl.

Running FastAPI With Uvicorn Step By Step

FastAPI application running locally with Uvicorn server

FastAPI is the most common framework people pair with Uvicorn because it is both fast and pleasant to write. To set it up from scratch, install the packages:

pip install fastapi
pip install "uvicorn[standard]"

Create a small app in main.py:

from fastapi import FastAPI

app = FastAPI()

@app.get("/") async def read_root(): return {"status": "ok"}

Now start the server in development:

uvicorn main:app --reload

main again points to main.py, app is the FastAPI instance, and reload watches your files so code changes restart the server. Open a browser and go to:

  • http://localhost:8000/ to see the JSON response
  • http://localhost:8000/docs for the interactive documentation

The automatic documentation helps:

  • Product managers explore endpoints without reading code
  • QA teams verify expected behavior
  • Developers try new endpoints as they build them

Tip: Use the --port flag (for example, --port 5000) if port 8000 is already taken on your machine.

Running Uvicorn Programmatically In Python Code

Sometimes you want to start Uvicorn from Python code instead of a shell, for example inside a management script or a larger asyncio program. In that case you can call uvicorn.run or configure a Server instance directly.

import uvicorn

if name == "main": uvicorn.run("main:app", host="0.0.0.0", port=5000, log_level="info")

This pattern is handy when:

  • You deploy with a single python main.py entrypoint
  • You want to read configuration from environment variables before starting the server
  • You run Uvicorn as part of a custom script on a platform without easy shell access

For more control, you can build a Config and Server, then await server.serve inside an existing event loop. When you need your app created at runtime, Uvicorn’s factory mode lets you expose a function like create_app and start it with the factory flag so the server calls that function before serving traffic.

How Do You Deploy Uvicorn To Production?

Server infrastructure representing production Uvicorn deployment

Deploying Uvicorn to production means running multiple workers behind a stable process manager and, often, a reverse proxy like Nginx. You want enough workers to handle your expected concurrency and a way to restart them cleanly during deploys. In many Python stacks, that job falls to Gunicorn plus a small Uvicorn worker package, although Uvicorn itself can run several workers without Gunicorn for smaller apps.

In production, you rarely use the reload flag because file watching adds overhead and surprises. Instead, you keep configuration in environment variables or a config store, set a fixed number of workers, and let a tool such as systemd or Docker compose restart failed processes. When budget and time are tight, a simple setup with Uvicorn workers behind Nginx on a single EC2 instance already gives a decent mix of reliability and latency.

A typical setup looks like this:

  • Nginx or Traefik:

    • Terminates TLS
    • Handles HTTP/2 and redirects
    • Proxies HTTP traffic to Uvicorn or Gunicorn on an internal port
  • Gunicorn (optional but common):

    • Manages worker processes
    • Handles graceful restarts during deploys
  • Uvicorn:

    • Runs the ASGI app in each worker
    • Handles async I/O and protocol details

Should You Pair Uvicorn With Gunicorn?

Pairing Uvicorn with Gunicorn is still a strong default for Python APIs that handle real traffic. Gunicorn manages worker processes and restarts, while Uvicorn workers handle async I/O and ASGI details. To use this combo, first install the worker package:

python -m pip install uvicorn-worker

Then start your app with a command similar to:

gunicorn example:app -w 4 -k uvicorn.workers.UvicornWorker

example:app points to your module and ASGI app, w 4 starts four worker processes, and the worker class hooks Uvicorn into Gunicorn. On PyPy, you can switch to the UvicornH11Worker class, which uses a pure Python HTTP stack better suited to that runtime.

A few practical tips for this stack:

  • Start with workers equal to 2–4 times your CPU core count, then adjust based on metrics
  • Use environment variables (like PORT and LOG_LEVEL) instead of hard‑coding ports
  • Configure systemd or your container platform to restart Gunicorn if it exits

Tip: Log access and errors to stdout/stderr in containers so your platform can capture them centrally.

Are There Alternatives To Uvicorn?

Alternatives to Uvicorn are useful when you have special protocol or hosting needs. Daphne comes from the Django Channels world and supports HTTP/2 along with WebSockets out of the box. Hypercorn supports both asyncio and Trio, which helps teams that prefer Trio’s structured concurrency model. Mangum sits in front of AWS Lambda with API Gateway, giving you a bridge from ASGI apps to serverless hosting. Granian takes a different path by implementing an ASGI compatible server in Rust, targeting even lower latencies and TLS features.

For most FastAPI and Starlette backends that run on regular servers or containers, Uvicorn stays the easiest and most common choice.

When evaluating alternatives, consider:

  • Runtime: CPython, PyPy, or a serverless environment
  • Protocol needs: HTTP/1.1 only, or HTTP/2 and WebSockets
  • Operational fit: Does your current team already use Gunicorn or similar tools?

Where Does Ahmed Hasnain Fit Into Your Python Backend Setup?

Full-stack developer planning Python backend architecture

This section explains how a product-focused full-stack developer fits into decisions about Uvicorn, FastAPI, and production hosting. When your team is small, the person wiring up the ASGI server is often the same person designing endpoints and thinking about user flows.

The developer behind this site works across Laravel, React, Vue, Next.js, and Python for SaaS, healthcare, and ecommerce products. On recent work with tools like Replug at D4 Interactive and hospital systems at Care Soft, strong backend structure mattered as much as UI polish. His workflow leans on AI tools such as Claude and ChatGPT for configuration research, error triage, and edge case tests, which shortens the time from “Uvicorn will not start” to “traffic is flowing behind Gunicorn and Nginx.” For founders and CTOs, that mix of product sense and practical backend setup help can save a lot of calendar time.

In practice, that kind of developer tends to:

  • Choose between minimal and standard installs based on real constraints
  • Wire up observability early so slow routes show up in metrics, not in support tickets
  • Keep deploy scripts simple enough that the rest of the team can understand and adjust them

The Takeaway

Uvicorn gives Python teams a clean way to run async apps, especially when paired with FastAPI and Starlette. With a standard install, you get a faster event loop, better HTTP parsing, and helpers that make local development smoother. In production, a small amount of upfront thought around workers, Gunicorn, and reverse proxies pays off later as traffic grows and outages become harder to accept.

Getting this server layer right early means you fight less with slow endpoints, stuck connections, and fragile deploy scripts. When a product‑minded full‑stack engineer like Ahmed Hasnain handles both API design and Uvicorn deployment, your SaaS backend tends to feel calmer and easier to extend.

Tip: Document the exact Uvicorn and Gunicorn commands you use in a README or runbook so onboarding new developers takes hours instead of days.

Frequently Asked Questions

Question: Is Uvicorn a web framework or a web server?

Uvicorn is a web server, not a framework. It runs ASGI applications built with frameworks such as FastAPI, Starlette, or Django Channels and handles HTTP and WebSocket connections while your framework handles routing and business logic.

Question: Can Uvicorn run Django applications?

Yes, Uvicorn can run Django applications when Django is configured for ASGI instead of only WSGI. With Django’s ASGI support or Django Channels, you expose an ASGI application object, then point Uvicorn or Gunicorn plus Uvicorn workers at that object just like you do with FastAPI.

Question: Does Uvicorn support HTTPS?

Uvicorn can serve HTTPS directly by loading certificate and key files through its SSL related command line flags. Many production teams instead place Nginx, Traefik, or another reverse proxy in front of Uvicorn to handle TLS, redirects, and HTTP/2, while Uvicorn listens on plain HTTP inside the network.

Question: Why is my Uvicorn server slow under load?

A Uvicorn server often feels slow under load when it runs without the standard extras, uses too few workers, or contains blocking code inside async routes. Start by installing uvicorn[standard], increasing workers, and checking for sync database calls or heavy CPU loops. For higher loads, combine Uvicorn with Gunicorn and watch metrics for queue time and response time.

Question: Can I use Uvicorn without Gunicorn in production?

You can run Uvicorn alone in production by using its workers flag to spawn multiple worker processes. For small services or internal tools, that is often enough. As your SaaS grows, a Gunicorn plus Uvicorn worker setup usually gives nicer process management, smoother restarts, and more predictable scaling behavior.

More Writing

React Performance Optimization Techniques That Actually Work
Aug 24, 202611 min read

React Performance Optimization Techniques That Actually Work

Learn proven react performance optimization techniques, from bundle size cuts to memoization and SSR, used to slash load times in real production apps.

react performance optimization techniques
Read Article
Server Side Rendering vs Client Side Rendering: Full Guide
Aug 20, 202611 min read

Server Side Rendering vs Client Side Rendering: Full Guide

Server side rendering vs client side rendering compared for SEO, speed, and cost, plus when to choose SSG for landing pages, dashboards, and bio-link pages.

server side rendering vs client side rendering
Read Article