WSGI vs ASGI — Common Interview Questions and Answers
1. What is WSGI?
WSGI (Web Server Gateway Interface) is a standard interface between Python web applications and web servers. It was defined in PEP 3333. It is synchronous: the server calls the application with a request and waits for a single response. One request is handled per call; blocking I/O blocks the worker.
2. What is ASGI?
ASGI (Asynchronous Server Gateway Interface) is an async variant of WSGI. It supports:
- Async/await: Non-blocking request handling
- Multiple events per connection: Long-polling, WebSockets, SSE
- Lifecycle hooks: Startup/shutdown and per-connection lifecycle
It is the basis for frameworks like FastAPI, Starlette, and Django Channels.
3. What is the main difference between WSGI and ASGI?
| Aspect | WSGI | ASGI |
|---|---|---|
| Model | Synchronous | Asynchronous |
| One request | One call, one response | Can handle many events |
| Blocking I/O | Blocks the worker | Doesn’t block (async I/O) |
| WebSockets | Not in the standard | Native support |
| HTTP/2 | Typically one req/resp | Can handle streams |
| Frameworks | Flask, Django (sync) | FastAPI, Starlette, Channels |
4. Why was ASGI created?
WSGI is synchronous and one-request-per-connection. ASGI was created to:
- Support async/await and non-blocking I/O
- Support WebSockets and long-lived connections
- Support HTTP/2 and other protocols
- Allow one process to handle many concurrent connections efficiently
5. What does a WSGI application look like?
A WSGI app is a callable (function or object with __call__) that takes environ and start_response, and returns an iterable of response body bytes:
def application(environ, start_response):
status = "200 OK"
headers = [("Content-Type", "text/plain")]
start_response(status, headers)
return [b"Hello, WSGI!"]
environ is a dict with request data; start_response is used to send status and headers.
6. What does an ASGI application look like?
An ASGI app is an async callable that receives scope, receive, send:
async def application(scope, receive, send):
if scope["type"] == "http":
await send({
"type": "http.response.start",
"status": 200,
"headers": [[b"content-type", b"text/plain"]],
})
await send({
"type": "http.response.body",
"body": b"Hello, ASGI!",
})
scope holds connection info; receive/send are async callables for reading and sending events.
7. Can you use a WSGI app with an ASGI server?
Yes. ASGI servers (e.g. Uvicorn, Hypercorn) often provide a WSGI-to-ASGI adapter so you can run Flask or Django (WSGI) behind them:
# Example: running a WSGI app with Uvicorn
from uvicorn.middleware.wsgi import WSGIMiddleware
from flask import Flask
flask_app = Flask(__name__)
# Wrap WSGI app for ASGI
app = WSGIMiddleware(flask_app)
The adapter runs the WSGI app in a thread pool, so you don’t get full async benefits, but it runs.
8. What are common WSGI servers?
- Gunicorn: Widely used, pre-fork workers, good for production
- uWSGI: Feature-rich (process management, static files, caching)
- Waitress: Pure Python, cross-platform
- mod_wsgi: Runs inside Apache
9. What are common ASGI servers?
- Uvicorn: Common with FastAPI/Starlette, uses uvloop
- Hypercorn: Supports HTTP/2, QUIC, same interface as Uvicorn
- Daphne: Used with Django Channels
- Granian: Rust-based ASGI server
10. When should you choose ASGI over WSGI?
Prefer ASGI when:
- You need async I/O (many concurrent connections, I/O-bound work)
- You use WebSockets or long-lived connections
- You use FastAPI, Starlette, or Django Channels
Prefer WSGI when:
- App is fully synchronous (e.g. classic Flask/Django views)
- You want maximum compatibility with existing WSGI middleware and servers
- Workload is CPU-bound (async doesn’t help much; use more workers instead)
11. Does using ASGI always make the app faster?
Not always. ASGI helps when:
- Many concurrent I/O-bound requests (DB, HTTP, file I/O) and you use async libraries
It does not help when:
- Work is CPU-bound (blocking the event loop)
- You use blocking DB/HTTP libraries inside async code
So “ASGI = faster” only when the app is written to be non-blocking and I/O-bound.
12. What is the relationship between ASGI and HTTP?
ASGI is protocol-agnostic. The same interface can handle:
- HTTP (request/response)
- WebSocket (connect, receive, send, disconnect)
- Lifespan (startup/shutdown)
The scope["type"] tells the app which protocol is in use (e.g. "http", "websocket").
13. What is an ASGI “scope”?
scope is a dict describing the connection. It is read-only and exists for the connection’s lifetime. For HTTP it typically includes:
type: e.g."http"method,path,query_stringheadersclient,server- etc.
For WebSocket, type is "websocket" and scope includes connection metadata.
14. How do “receive” and “send” work in ASGI?
- receive: Async callable that returns the next event (e.g.
http.requestbody chunks,websocket.receivemessages). You await it when you need more data. - send: Async callable you call to send events (e.g.
http.response.start,http.response.body,websocket.send).
They form a single producer/consumer channel per connection.
15. Is Django WSGI or ASGI?
Django supports both:
- WSGI: Traditional request/response (default); use with Gunicorn/uWSGI.
- ASGI: For async views, async middleware, and Django Channels (WebSockets, background tasks). Use with Daphne/Uvicorn/Hypercorn and an ASGI config in
asgi.py.
Same project can be served via WSGI or ASGI depending on deployment and features needed.
Interview angle
- “WSGI or ASGI?” - WSGI is synchronous, one request per worker thread or process, and cannot express WebSockets or long-lived connections. ASGI is async-native and handles HTTP, WebSockets and lifespan events. New Python web work targets ASGI.
- “Does ASGI make everything faster?” - only for I/O-bound concurrency. CPU-bound work gains nothing and actively harms other requests by occupying the event loop.
- “Can you run sync code under ASGI?” - yes, frameworks run it in a threadpool. That’s why a plain
defroute in FastAPI is safe while a blocking call insideasync defis not.