backend / web frameworks / 00_wsgi_vs_asgi.md

WSGI vs ASGI — Common Interview Questions and Answers

3 interview angles 4 min read source

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_string
  • headers
  • client, 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.request body chunks, websocket.receive messages). 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 def route in FastAPI is safe while a blocking call inside async def is not.