Granian
A Rust HTTP server for Python applications
Install / Use
/learn @emmett-framework/GranianREADME
Granian is a Rust HTTP server for Python applications built on top of Hyper and Tokio.
Rationale
The main reasons behind Granian design are:
- Have a single, correct HTTP implementation, supporting versions 1, 2 (and eventually 3)
- Provide a single package for several platforms
- Avoid the usual Gunicorn + uvicorn + http-tools dependency composition on unix systems
- Provide stable performance when compared to existing alternatives
Adopting Granian would thus be a good choice when:
- wanting a modern, single dependency to serve both ASGI and WSGI applications
- looking for the most performant way to serve your Python application under HTTP/2
- you need great concurrency capabilities, especially with websockets
- you care about throughput more than everything else
On the other hand, Granian won't be the ideal option if:
- you want a pure Python solution
- you need advanced debugging features
- your application relies on
trioorgevent - you're looking for ASGI extensions not (yet) implemented
Features
- Supports ASGI/3, RSGI and WSGI interface applications
- HTTP/1 and HTTP/2 protocols
- HTTPS and mTLS
- Websockets
- Direct static files serving
- ASGI pathsend extension
Quickstart
You can install Granian using pip:
$ pip install granian
ASGI
Create an application in your main.py:
async def app(scope, receive, send):
assert 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, world!',
})
and serve it using Granian CLI:
$ granian --interface asgi main:app
RSGI
Create an application your main.py:
async def app(scope, proto):
assert scope.proto == 'http'
proto.response_str(
status=200,
headers=[
('content-type', 'text/plain')
],
body="Hello, world!"
)
and serve it using Granian CLI:
$ granian --interface rsgi main:app
WSGI
Create an application your main.py:
def app(environ, start_response):
start_response('200 OK', [('content-type', 'text/plain')])
return [b"Hello, world!"]
and serve it using Granian CLI:
$ granian --interface wsgi main:app
Extra dependencies
Mind that Granian also provides several extra dependencies you might be interested into, in particular:
- dotenv (allows to load environment files)
- pname (allows to customize processes' names)
- reload (adds reload on changes functionality)
- rloop
- uvloop
- winloop
You can combine the above extras to suit your needs, eg:
$ pip install granian[pname,uvloop]
For further information, check the options below.
Options
You can check all the options provided by Granian with the --help command:
$ granian --help
Usage: granian [OPTIONS] APP
APP Application target to serve. [required]
Options:
--host TEXT Host address to bind to [env var:
GRANIAN_HOST; default: (127.0.0.1)]
--port INTEGER Port to bind to. [env var: GRANIAN_PORT;
default: 8000]
--uds PATH Unix Domain Socket to bind to. [env var:
GRANIAN_UDS]
--uds-permissions OCTAL INTEGER
Unix Domain Socket file permissions [env
var: GRANIAN_UDS_PERMISSIONS]
--interface [asgi|asginl|rsgi|wsgi]
Application interface type [env var:
GRANIAN_INTERFACE; default: (rsgi)]
--http [auto|1|2] HTTP version [env var: GRANIAN_HTTP;
default: (auto)]
--ws / --no-ws Enable websockets handling [env var:
GRANIAN_WEBSOCKETS; default: (enabled)]
--workers INTEGER RANGE Number of worker processes [env var:
GRANIAN_WORKERS; default: 1; x>=1]
--blocking-threads INTEGER RANGE
Number of blocking threads (per worker)
[env var: GRANIAN_BLOCKING_THREADS; x>=1]
--blocking-threads-idle-timeout DURATION
The maximum amount of time in seconds (or a
human-readable duration) an idle blocking
thread will be kept alive [env var:
GRANIAN_BLOCKING_THREADS_IDLE_TIMEOUT;
default: 30; 5<=x<=600]
--runtime-threads INTEGER RANGE
Number of runtime threads (per worker) [env
var: GRANIAN_RUNTIME_THREADS; default: 1;
x>=1]
--runtime-blocking-threads INTEGER RANGE
Number of runtime I/O blocking threads (per
worker) [env var:
GRANIAN_RUNTIME_BLOCKING_THREADS; x>=1]
--runtime-mode [auto|mt|st] Runtime mode to use (single/multi threaded)
[env var: GRANIAN_RUNTIME_MODE; default:
(auto)]
--loop [auto|asyncio|rloop|uvloop|winloop]
Event loop implementation [env var:
GRANIAN_LOOP; default: (auto)]
--task-impl [asyncio|rust] Async task implementation to use [env var:
GRANIAN_TASK_IMPL; default: (asyncio)]
--backlog INTEGER RANGE Maximum number of connections to hold in
backlog (globally) [env var:
GRANIAN_BACKLOG; default: 1024; x>=128]
--backpressure INTEGER RANGE Maximum number of requests to process
concurrently (per worker) [env var:
GRANIAN_BACKPRESSURE; default:
(backlog/workers); x>=1]
--http1-buffer-size INTEGER RANGE
Sets the maximum buffer size for HTTP/1
connections [env var:
GRANIAN_HTTP1_BUFFER_SIZE; default: 417792;
x>=8192]
--http1-header-read-timeout INTEGER RANGE
Sets a timeout (in milliseconds) to read
headers [env var:
GRANIAN_HTTP1_HEADER_READ_TIMEOUT; default:
30000; 1<=x<=60000]
--http1-keep-alive / --no-http1-keep-alive
Enables or disables HTTP/1 keep-alive [env
var: GRANIAN_HTTP1_KEEP_ALIVE; default:
(enabled)]
--http1-pipeline-flush / --no-http1-pipeline-flush
Aggregates HTTP/1 flushes to better support
pipelined responses (experimental) [env
var: GRANIAN_HTTP1_PIPELINE_FLUSH; default:
(disabled)]
--http2-adaptive-window / --no-http2-adaptive-window
Sets whether to use an adaptive flow control
for HTTP2 [env var:
GRANIAN_HTTP2_ADAPTIVE_WINDOW; default:
(disabled)]
--http2-initial-connection-window-size INTEGER RANGE
Sets the max connection-level flow control
for HTTP2 [env var: GRANIAN_HTTP2_INITIAL_C
ONNECTION_WINDOW_SIZE; default: 1048576;
x>=1024]
--http2-initial-stream-window-size INTEGER RANGE
Sets the `SETTINGS_INITIAL_WINDOW_SIZE`
option for HTTP2 stream-level flow control
[env var:
GRANIAN_HTTP2_INITIAL_STREAM_WINDOW_SIZE;
default: 1048576; x>=1024]
--http2-keep-alive-interval INTEGER RANGE
Sets an interval (in milliseconds) for HTTP2
Ping frames should be sent to keep a
connection alive [env var:
GRANIAN_HTTP2_KEEP_ALIVE_INTERVAL;
1<=x<=60000]
--http2-keep-alive-timeout DURATION
Sets a timeout (in seconds or a human-
readable duration) for receiving an
acknowledgement of the HTTP2 keep-alive ping
[env var: GRANIAN_HTTP2_KEEP_ALIVE_TIMEOUT;
default: 20; x>=1]
--http2-max-concurrent-streams INTEGER RANGE
Sets the SETTINGS_MAX_CONCURRENT_STREAMS
option
Related Skills
himalaya
335.2kCLI to manage emails via IMAP/SMTP. Use `himalaya` to list, read, write, reply, forward, search, and organize emails from the terminal. Supports multiple accounts and message composition with MML (MIME Meta Language).
node-connect
335.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
claude-opus-4-5-migration
82.5kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
frontend-design
82.5kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
