gunicorn review
Gunicorn 26.2.0 is a Unix application server that binds an HTTP socket and supervises worker processes running Python WSGI or ASGI applications. Its master handles signals, worker replacement, graceful reloads, timeouts, and process-level concurrency; Django, Flask, FastAPI, or another framework still owns request handling. Version 26.2 adds cleartext HTTP/2 modes for trusted proxy hops and fixes HTTP/2 header-policy bypasses, response buffering, flow-control data loss, and no-body responses. HTTP/2 remains labeled beta, and the project warns against exposing an h2c port directly to the internet.
Gunicorn 26.1.0 installed in 0.2 seconds and imported in 0.01 seconds in our sandbox; current 26.2.0 is a strong Unix supervisor for WSGI and ASGI workers, especially behind an existing proxy. Do not add it to native Windows or already-supervised ASGI deployments, and treat the new h2c path as a trusted internal hop.
We installed it
| Install | ✓ · 0.2s | 1 package on disk · 1 MB |
| Import | ✓ | import gunicorn in 0.01s · pure Python · requires Python >=3.10 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does gunicorn install cleanly?
Yes. In a fresh container with an empty cache, pip install gunicorn finished in 0.2s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.
What does gunicorn need to run?
Python >=3.10, and nothing compiled: it is pure Python. In our run import gunicorn succeeded in 0.01s.
gunicorn or uvicorn: which should you use?
Pick uvicorn when uvicorn 0.x is the direct choice for an ASGI app when one process or external process supervision is enough. Gunicorn 26.1.0 installed in 0.2 seconds and imported in 0.01 seconds in our sandbox; current 26.2.0 is a strong Unix supervisor for WSGI and ASGI workers, especially behind an existing proxy.
When should you not use gunicorn?
The service must run natively on Windows. Gunicorn relies on Unix process forking, file descriptors, and signals for its normal control model.
Use it if
- Gunicorn 26.2.0 fits a Unix deployment that needs one master to bind a socket and supervise several WSGI or ASGI workers.
- A Django or Flask service should reload code gracefully through signals while an existing proxy buffers slow clients.
- You need a choice among sync, gthread, gevent, and ASGI workers without changing the application's import target.
- A trusted TLS-terminating proxy should speak h2c to Gunicorn 26.2 while the public cleartext port remains closed.
- The service must run natively on Windows. Gunicorn relies on Unix process forking, file descriptors, and signals for its normal control model.
- A pure ASGI service already runs well under Uvicorn or Hypercorn and the platform supplies process supervision; another master process may add no useful boundary.
- Sync workers will face slow internet clients without a buffering proxy. Gunicorn's deployment documentation places nginx or a comparable proxy ahead of that worker class.
- Your configuration still names the eventlet worker. Gunicorn 26 removed it, leaving gevent, gthread, tornado, sync, and ASGI paths.
- HTTP/2 must be mature and enabled by default. The README calls it beta, and cleartext HTTP/2 is off until http2_cleartext is configured.
- You expect one worker to share in-memory sessions, caches, or locks with another. Forked workers have separate Python heaps.
Setup reality
We installed Gunicorn 26.1.0, the supplied lab version, in a fresh Python 3.12 Bookworm sandbox. Installation took 0.2 seconds, left 1 package, and used 1 MB. pip-audit reported 0 known vulnerabilities. The package metadata counted 16 direct dependencies, requires Python >=3.10, and is pure Python. import gunicorn completed in 0.01 seconds. It does not ship py.typed, and the measured package license field was unknown.
PyPI now serves 26.2.0, so those install figures do not claim to measure the newer release. The basic command is gunicorn module:app; an application factory uses module:create_app(). Choose workers and bind addresses in CLI flags, GUNICORN_CMD_ARGS, or a Python config file. A config file executes as Python, which is convenient for environment-based values but also means it should be reviewed like code.
Worker count is capacity planning, not a magic CPU formula. Sync workers process one request each; gthread adds threads; gevent requires cooperative libraries; ASGI handles async applications and websockets. preload_app can reduce memory through copy-on-write, but it imports application state before forking. Database connections, background threads, and random state created during preload may need post-fork initialization.
Put sync workers behind a proxy that buffers slow clients, set forwarded_allow_ips to the actual trusted proxy addresses, and do not accept forwarded headers from arbitrary peers. Version 26.2's h2c modes are meant for a trusted internal hop after TLS termination. Graceful reload uses HUP, while TTIN and TTOU adjust workers. timeout kills workers that remain silent, so long jobs belong outside request workers or need a deliberate worker and timeout design.
Patterns
Start four WSGI workers serve-wsgi
gunicorn myapp:app --bind 127.0.0.1:8000 --workers 4Four workers have four separate Python heaps. Bind to loopback when nginx or another local proxy owns the public socket.
Call an application factory serve-factory
gunicorn 'myapp:create_app()' --workers 3Quote the target so the shell does not interpret parentheses. The factory runs inside the Gunicorn application loading path.
Run an ASGI application serve-asgi
gunicorn myapp:app --worker-class asgi --workers 2The ASGI worker is for async frameworks and websocket handling. Test lifespan and disconnect behavior on the deployed Gunicorn version.
Keep worker settings in Python configure-python
# gunicorn.conf.py
bind = '127.0.0.1:8000'
workers = 4
worker_class = 'gthread'
threads = 8
timeout = 30
graceful_timeout = 30
accesslog = '-'
errorlog = '-'Gunicorn executes this file as Python. Keep secrets in the process environment and review config changes as executable code.
Limit requests per worker recycle-workers
gunicorn myapp:app --max-requests 2000 --max-requests-jitter 200The random 0 to 200 request offset prevents every worker from restarting after the same request count.
Trust one proxy address trust-proxy
gunicorn myapp:app --forwarded-allow-ips 10.0.0.12Forwarded scheme and related headers are trusted only from this address. Do not use * on a socket reachable by untrusted clients.
Reload code and configuration gracefully reload-master
kill -HUP "$(cat /run/gunicorn/pid)"HUP asks the master to reload configuration and replace workers while retaining listeners. Verify the pidfile target before sending the signal.
Accept prior-knowledge h2c from a proxy enable-h2c
# gunicorn.conf.py
http2_cleartext = 'prior-knowledge'
forwarded_allow_ips = '10.0.0.12'Gunicorn 26.2 restricts h2c handling to trusted forwarded_allow_ips peers. Keep this cleartext port off the public internet.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| uvicorn | PyPI | uvicorn 0.x is the direct choice for an ASGI app when one process or external process supervision is enough. |
| waitress | PyPI | Use Waitress for a pure-Python WSGI server that also supports Windows deployments. |
| hypercorn | PyPI | Use Hypercorn when ASGI plus HTTP/2 or Trio support is central and Gunicorn's prefork heritage adds little. |
More web backend guides
urllib3 · requests · ws · anyio · httpx · undici · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

