
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.
Blog Post
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.

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 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.
Table of Contents
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:
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.
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:
Prefer ASGI and Uvicorn when:
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:
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.
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.
| Aspect | Minimal Install | Standard Install |
|---|---|---|
| Core packages | click, h11, typing-extensions | Same core packages |
| Performance helpers | Pure Python only | Adds uvloop, httptools, websockets |
| Developer comfort | No reload or env file helpers | Adds watchfiles, python-dotenv, PyYAML |
| Typical use | Tiny tools, experiments | Most 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:
Use standard for:
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:
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:
Then you can open http://127.0.0.1:8000/ in a browser or call it with curl.
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 FastAPIapp = 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:
The automatic documentation helps:
Tip: Use the --port flag (for example, --port 5000) if port 8000 is already taken on your machine.
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:
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.
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:
Gunicorn (optional but common):
Uvicorn:
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:
Tip: Log access and errors to stdout/stderr in containers so your platform can capture them centrally.
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:
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:
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.
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.

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

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.