Skip to content

WSGI Concepts

When you run a Flask app, there’s always a “server” involved.

But your Flask code is just Python functions. So how does an HTTP request become a Python function call?

That bridge is WSGI.

What is WSGI?

WSGI stands for Web Server Gateway Interface.

It’s a Python standard that defines a simple contract between:

  • a WSGI server (Gunicorn, uWSGI, Waitress)
  • a WSGI app (Flask app)

The goal: any WSGI server can run any WSGI-compatible Python web app.

The simplest WSGI mental model

A WSGI server:

  1. Accepts an HTTP request from the network
  2. Builds an environenviron dictionary (details about the request)
  3. Calls your Flask app like a Python callable
  4. Receives the response body iterator
  5. Sends bytes back to the client

false


  flowchart LR
  C[Client] -->|HTTP| WS[WSGI Server]
  WS -->|environ + start_response| F[Flask (WSGI App)]
  F -->|status, headers, body| WS
  WS -->|HTTP Response| C

false

Dev server vs WSGI server

When you run:

  • flask runflask run

Flask uses a development server (Werkzeug).

It is:

  • fine for local development
  • not designed for heavy production workloads
  • not tuned for security/hardening

In production, you typically run Flask behind:

  • Gunicorn (WSGI server) and often
  • Nginx (reverse proxy for TLS, caching, static files, etc.)

Where does “WSGI app” live in Flask?

If you have:

from flask import Flask
app = Flask(__name__)
from flask import Flask
app = Flask(__name__)

appapp is a WSGI application callable.

WSGI servers point to it like:

  • gunicorn "app:app"gunicorn "app:app"

Meaning: import the module app.pyapp.py, then use the appapp variable.

Why you should care

Understanding WSGI helps you debug:

  • “It works locally but not in production.”
  • incorrect host/port binding
  • reverse proxy headers (X-Forwarded-For)
  • timeouts and worker model issues

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did