Skip to content

Environment variables

Defaults and enforcement scope are generated from the Settings and AppConfig declarations in blackbull/env.py and blackbull/config.py. See Configuration for startup-setting precedence; BB_* runtime tuning is a separate namespace. Most settings are cached on first use, and import-time settings require a restart. A value that does not parse, or is outside a setting's range, falls back to its default.

Deployment

These resolve with run() precedence: an explicit argument, then the variable, then a .env entry, then AppConfig.

The BLACKBULL_* names move to BB_*

BLACKBULL_ENV and the variables below will be renamed to the BB_ prefix (BBD008), so that every setting shares one namespace. Until then only the BLACKBULL_ names are read.

Variable Default Controls
BLACKBULL_CERT (unset) TLS certificate file. Enables HTTPS, and therefore HTTP/2 via ALPN, when paired with the key.
BLACKBULL_KEY (unset) TLS private key file. Required alongside the certificate for HTTPS and HTTP/2.
BLACKBULL_PORT 0 TCP port to bind. 0 lets the OS pick a free ephemeral port.
BLACKBULL_UNIX_PATH (unset) AF_UNIX socket path. Mutually exclusive with a TCP port bind.
BLACKBULL_RELOAD 0 Enable auto-reload (1, true, yes or on; requires the [reload] extra).

Runtime and processes

Variable Default Controls
BLACKBULL_ENV development production | development | test. In production, StaticFiles declines to serve files (production should sit behind nginx/Caddy for static assets), and the default error handler returns a terse response without exception details; in development it shows them to a loopback peer without Forwarded/X-Forwarded-For only.
BB_WORKERS 1 Pre-fork worker count. 0 resolves to os.cpu_count(). Combine with BB_SOCKET_REUSEPORT=1, except under --reload or on a port-bound non-ASGI protocol, which keep one listener. See Workers.
BB_UVLOOP 0 Install uvloop's asyncio policy at startup. Requires pip install 'blackbull[speed]'; falls back to the standard loop with a warning when uvloop is missing.
BB_FORCE_ASGI_SCOPE 0 Exercise the native-to-ASGI compatibility conversion on every request. Leave off for normal native serving.
BB_CPU_PINNING auto Linux multi-worker event-loop CPU placement. auto assigns workers within the inherited CPU mask; off disables pinning; a taskset-style list intersects that mask (0 means CPU 0). Executor threads keep the full mask. Single-worker servers are not pinned. Use off when placement is managed externally.

Warm-up

Warm-up runs any hooks registered with @app.on_warmup once, in the master, before the listening socket is created and before workers fork, so every worker inherits the warmed heap (specialized bytecode, primed codecs/TLS) via copy-on-write. These knobs only matter when the app registers at least one warm-up hook; with none, warm-up is a no-op.

Variable Default Controls
BB_WARMUP_BUDGET_S 60.0 Hard wall-clock cap (seconds) on total warm-up. A hook that overruns is cancelled and the master proceeds to bind — warm-up is best-effort and never blocks boot indefinitely.
BB_WARMUP_TLS_N 64 Number of in-memory (ssl.MemoryBIO) TLS handshakes the framework performs to prime the OpenSSL/RSA/ALPN path, when the listener terminates TLS. Runs automatically after the app's own warm-up hooks; 0 disables it.

Connection limits and timeouts

Every cap in this section (plus the HTTP/2, WebSocket, and Compression caps below) emits one WARNING record on the blackbull.caps logger when it fires. Subscribe to that logger to get a real-time signal when a deployment hits its configured limits — see Logging for the record shape, the inventory, and the per-connection first-hit-then-summary rate-limit model.

Variable Default Controls
BB_MAX_CONNECTIONS auto Concurrent TCP connections per worker. auto subtracts a 64-descriptor reserve and already-open descriptors from RLIMIT_NOFILE; 0 disables the cap. Explicit numbers are not clamped to the descriptor budget. Counted from accept, including TLS handshakes. Excess connections wait in the accept queue; HTTP/1.1 and prior-knowledge h2c receive best-effort 503 with Retry-After: 1; ALPN-h2 and raw connections close silently. During lifespan startup the backlog applies instead. Set an explicit cap if the application opens descriptors later. See startup admission.
BB_REQUEST_TIMEOUT 0.0 Seconds allowed for HTTP/1.1 handler dispatch or an HTTP/2 stream handler. A breach cancels the handler; HTTP/1.1 answers 408 and closes, HTTP/2 sends RST_STREAM(CANCEL) while sibling streams survive. 0 disables. Choose a budget compatible with intentional long-lived requests.
BB_HEADER_TIMEOUT 10.0 Seconds to complete an HTTP/1.1 request head (408 and close), an HTTP/2 field block (GOAWAY ENHANCE_YOUR_CALM), or a TLS handshake. TLS connections count from accept, including port-bound protocols. 0 disables this deadline; TLS then uses the event loop's own handshake timeout.
BB_BODY_TIMEOUT 30.0 Seconds per HTTP/1.1 request-body read after the head. A breach surfaces http.disconnect and tears down the connection; 0 disables. Does not bound an HTTP/2 stream's body reads: use its request deadline and body rate/size bounds.
BB_WRITE_TIMEOUT 30.0 Seconds the server will wait for a single response socket drain, sendfile chunk, or HTTP/2 flow-control wait. This is per progress wait, not a whole response total; an HTTP/2 stream that waits past it is reset with RST_STREAM(CANCEL), after at most the one response head already sent. 0 disables.
BB_KEEP_ALIVE_TIMEOUT 5.0 Seconds an idle HTTP/1.1 keep-alive connection is held open after a complete response. Lower for high-fan-in deployments; higher for chatty clients on slow links.
BB_TCP_USER_TIMEOUT_MS 0 TCP_USER_TIMEOUT socket option (Linux): per-connection upper bound on how long an unacknowledged sent segment lingers before the kernel kills the connection, evicting dead peers behind NATs without waiting for keepalives. 0 keeps the kernel default. See Per-path scope.
BB_HEADER_MAX_LINE 8192 Maximum bytes in an HTTP/1.1 request-line or field line. Oversized request lines receive 400; oversized header fields receive 431.
BB_HEADER_MAX_TOTAL 65536 Maximum bytes in the HTTP/1.1 request-line and header block (400/431). Also bounds HTTP/2 encoded blocks and decoded field sections (name + value + 32 per field, including pseudoheaders); excess sends GOAWAY ENHANCE_YOUR_CALM. The decoded bound is advertised as SETTINGS_MAX_HEADER_LIST_SIZE, capped at 2^32-1. 0 disables advertisement and opens that decoder bound to 2^32-1.
BB_BODY_CHUNK_SIZE 65536 Maximum read slice in bytes for chunked HTTP/1.1 request bodies, independent of peer-declared chunk size. Must be positive; invalid values use the default. Content-Length bodies use BB_BODY_CHUNK_MAX instead.
BB_BODY_CHUNK_MAX 524288 Maximum bytes materialized by one Content-Length body read. Reads return available bytes without waiting to fill the slice. Does not cap the total body or the chunked path. 0 is raised to 1.
BB_MAX_BODY_SIZE 31457280 (30 MiB) Total request-body bytes on HTTP/1.1 and HTTP/2. Declared over-cap lengths are refused before reading; undeclared totals are refused while accumulating. HTTP/1.1 sends 413 and closes. HTTP/2 sends 413 plus RST_STREAM(NO_ERROR) for a declared excess, or RST_STREAM(ENHANCE_YOUR_CALM) for a streaming excess; sibling streams survive. 0 disables.
BB_MIN_BODY_RATE 240.0 Minimum request-body bytes per second over a sliding grace-width window. Below the floor: HTTP/1.1 disconnects and closes; HTTP/2 resets the stream with ENHANCE_YOUR_CALM. A per-read timeout alone does not stop a trickle. 0 disables.
BB_MIN_BODY_RATE_GRACE 5.0 Seconds before the request-body rate floor applies; also its sliding-window width. HTTP/1.1 counts transport wait time, excluding slow handler work. HTTP/2 counts wall time from first DATA but exempts peers blocked by our closed inbound window.
BB_STREAM_QUEUE_DEPTH 64 Frame-count queue depth for HTTP/2 bodies without consume-time credit (direct/push fallback). Native request streams instead use the advertised byte window plus a frame-count abuse cap of 16 times this depth; this knob does not replace those bounds. A stream past either is reset with RST_STREAM ENHANCE_YOUR_CALM.
BB_WS_QUEUE_DEPTH 0 WebSocket read-ahead depth. 0 reads inline in the handler task; positive values buffer up to N messages in a background reader. A websocket_message observer does not force read-ahead: the idle watchdog starts a deferred reader when the handler goes quiet. See WebSockets.

Async HTTP client

Client caps are separate from server caps. A refusal emits a named record on blackbull.caps; conformance switches and grace-period modifiers do not. For failure types and buffered/streaming tradeoffs, see Client.

Variable Default Controls
BB_CLIENT_HEAD_MAX_TOTAL 65536 HTTP/1.1 response-head bytes including status line and terminator; excess raises ResponseTooLarge. HTTP/2 separately caps encoded field-block accumulation (GOAWAY ENHANCE_YOUR_CALM) and decoded fields across informational, final and trailer sections on one stream (stream refusal). Per-section decoded HPACK accounting is BB_CLIENT_H2_MAX_HEADER_LIST_SIZE. 0 disables.
BB_CLIENT_HEAD_MAX_LINE 8192 Bytes per HTTP/1.1 status, field, chunk-size or trailer line. Excess raises ResponseTooLarge. 0 disables; BB_CLIENT_HEAD_MAX_TOTAL separately bounds head accumulation.
BB_CLIENT_HEAD_TIMEOUT 30.0 Seconds per HTTP/1.1 response head; expiry raises TimeoutError and retires the connection. On HTTP/2 it separately bounds request-on-wire to final HEADERS (stream CANCEL), and an opened field block to END_HEADERS (connection ENHANCE_YOUR_CALM). Interims do not restart the HTTP/2 response-start clock. Long polls or work before headers must fit this budget. 0 disables all three waits.
BB_CLIENT_BODY_TIMEOUT 30.0 Seconds per response-body progress wait, not per whole response. HTTP/1.1 covers one payload arrival or complete framing operation. HTTP/2 applies per stream from final HEADERS, restarting only on non-empty DATA. Expiry raises TimeoutError; a trickle needs BB_CLIENT_MIN_BODY_RATE. 0 disables.
BB_CLIENT_WRITE_TIMEOUT 30.0 Seconds per client socket drain or HTTP/2 flow-control credit wait, separate from server BB_WRITE_TIMEOUT. No whole-upload deadline: repeated small credit grants can extend an upload indefinitely. H2 writes use the peer's frame-size setting; BB_CLIENT_H2_MAX_FRAME_SIZE is receive-only. 0 disables.
BB_CLIENT_BODY_MAX_TOTAL 0 Buffered response-body bytes on HTTP/1.1 and HTTP/2; excess raises ResponseTooLarge. Declared excess is refused before reading, other excess before retaining it. 0 disables. Budget at least twice this value plus per-slice overhead per concurrent response because joining retains both slices and result. HTTP/1.1 stream() bypasses accumulation and this cap but exposes neither status nor headers; HTTP/2 has no streaming API.
BB_CLIENT_MIN_BODY_RATE 0.0 Minimum sustained response-body payload rate in bytes per second, after BB_CLIENT_MIN_BODY_RATE_GRACE. The numerator is DATA payload only (HTTP/2 padding and frame overhead are excluded); the denominator is per-stream wait time, including empty/padded DATA and terminal DATA/trailing HEADERS settlement. The window starts at the first non-empty body payload, so think time after final HEADERS is excluded. HTTP/1.1 abandons its connection; HTTP/2 resets only the offending stream with RST_STREAM(CANCEL). Off by default; 0 disables.
BB_CLIENT_MIN_BODY_RATE_GRACE 5.0 Seconds of body-read waiting, after the first body octet, before BB_CLIENT_MIN_BODY_RATE is enforced. Also the width of the window the rate is averaged over: it rolls forward whenever it is satisfied, so a burst buys the window it happened in rather than the whole response. Under HTTP/2 this is per response stream.
BB_CLIENT_WS_MAX_FRAME_PAYLOAD 67108864 (64 MiB) Client WebSocket inbound payload bytes per frame (unit). Excess closes with 1009 and raises ProtocolError from receive(). BB_CLIENT_WS_MAX_MESSAGE_SIZE owns the aggregate message total. There is no client-owned WebSocket time bound here: the H1 session has no environment time owner, and H2 per-call receive timeouts are caller arguments, not this setting. 0 disables this unit cap.
BB_CLIENT_WS_MAX_MESSAGE_SIZE 16777216 (16 MiB) Client WebSocket inbound payload bytes per reassembled/inflated message (total). Excess closes with 1009 and raises ProtocolError from receive(). BB_CLIENT_WS_MAX_FRAME_PAYLOAD owns the per-frame unit. There is no client-owned WebSocket time bound here: the H1 session has no environment time owner, and H2 per-call receive timeouts are caller arguments, not this setting. 0 disables this total cap.
BB_CLIENT_MAX_INTERIM_RESPONSES 8 Interim 1xx heads discarded before the final response on either transport; 101 is final and not counted. Excess raises ResponseTooLarge. 0 disables. HTTP/1.1 spends the head byte/time budgets afresh per interim; HTTP/2 counts empty sections too and keeps its response-start deadline running.
BB_CLIENT_RAW_QUEUE_DEPTH 1024 Frames queued per raw HTTP/2 stream. Only DATA, RST_STREAM and HEADERS enter it. Overflow discards backlog, returns connection credit and resets only that stream with ENHANCE_YOUR_CALM, waking its consumer. DATA bytes remain consume-credited; depth additionally bounds empty frames. This is not a rate bound. 0 disables.
BB_CLIENT_H2_MAX_FRAME_SIZE 16384 Inbound HTTP/2 frame payload bytes checked before reading. Excess ends the connection with FRAME_SIZE_ERROR; unread payload cannot safely be skipped as a stream error. 0 disables. The client does not advertise a changed frame size: keep the RFC initial value outside fault-injection scenarios.
BB_CLIENT_H2_MAX_HEADER_LIST_SIZE 65536 Decoded HTTP/2 bytes per field section, counted as name + value + 32 per field. Advertised as SETTINGS_MAX_HEADER_LIST_SIZE and enforced inside HPACK decoding; excess ends the connection with COMPRESSION_ERROR. 0 disables advertisement and opens the decoder limit. Separate from per-stream BB_CLIENT_HEAD_MAX_TOTAL.
BB_CLIENT_H2_ENABLE_PUSH 1 HTTP/2 push policy. 1 decodes and discards promises without advertising a change. 0 advertises ENABLE_PUSH=0 and refuses promises with connection PROTOCOL_ERROR after its SETTINGS acknowledgement; in-flight promises before ACK remain legal. Promised blocks are always decoded to preserve shared HPACK state. No push-consuming API is provided.

Fault injection

Variable Default Controls
BB_PRODUCTION 0 Set to 1 to make the fault-injection servers refuse to start, in addition to the refusal that BLACKBULL_ENV=production already triggers.

Socket tuning

Variable Default Controls
BB_SOCKET_BACKLOG 1024 listen() backlog depth, sized for connection bursts; Linux caps the effective value at net.core.somaxconn. Where BlackBull binds, this value bounds the accept queue; an adopted fd keeps its creator's Backlog= until accepting begins; see The startup window. During that window a TCP client beyond the backlog is served late and a non-blocking AF_UNIX client is refused (details); an AF_UNIX queue found full when accepting opens is logged on blackbull.caps.
BB_SOCKET_REUSEPORT 0 Give each worker a separate TCP listening socket on supported systems. AF_UNIX is not rebound and cannot use this shape with multiple workers unless reload keeps a shared listener. An adopted fd whose supervisor retains ownership cannot be split this way. 0 keeps the kernel default. See socket scope.
BB_SOCKET_SNDBUF 0 SO_SNDBUF (bytes) on BlackBull's own listeners and the TCP connections accepted from them; 0 keeps the kernel default. Linux clamps at net.core.wmem_max and doubles. See Per-path scope.
BB_SOCKET_RCVBUF 0 SO_RCVBUF (bytes) in the same scope as BB_SOCKET_SNDBUF, against net.core.rmem_max instead and doubled by the same rule. 0 keeps the kernel default.

Logging

Variable Default Controls
BB_ACCESS_LOG 1 Emit one record on the blackbull.access logger per completed request. Set to 0 to skip access-log formatting (useful during benchmarks).
BB_ASYNC_LOGGING 1 Install a QueueHandler on the blackbull logger so logger.debug/info calls from the event loop are non-blocking.
BB_LOG_FORMAT (unset) Set to json to emit one structured JSON object per log line. Access-log records expose client_ip, method, path, http_version, status, response_bytes, duration_ms (plus close_code on WebSocket disconnect) as top-level keys; every record carries timestamp, level, logger, message. Applies to the default sink installed by async logging. Unset means plain text.
BB_SYSLOG_ADDR (unset) host:port of a syslog/UDP collector (e.g. 127.0.0.1:514). When set, the async-logging sink ships records via a UDP SysLogHandler instead of stderr. Composes with BB_LOG_FORMAT=json. An unparseable value falls back to stderr with a warning.
BB_LOG_FILE (unset) Append-file path for the async logging sink, opened separately in each worker after fork. Ignored with syslog. An unopenable path warns and falls back to stderr. Composes with JSON formatting and batch size.
BB_LOG_BATCH_SIZE 64 Records per async stream/file batch, floored at 2. Partial batches flush after BB_LOG_BATCH_TIMEOUT_MS. Use BB_ASYNC_LOGGING=0 for synchronous per-record flushes. Syslog remains one datagram per record.
BB_LOG_BATCH_TIMEOUT_MS 5 Max time a partial batch waits before it is flushed, bounding log-visibility latency at low request rates.

The blackbull.caps logger has no env-var toggle — set its level via logging.getLogger('blackbull.caps').setLevel(...) at startup. Default level is WARNING; raise to ERROR to silence or drop to INFO to surface the rate-limit summary records.

Static files

Variable Default Controls
BB_STATIC_STAT_TTL_S 1.0 Seconds between cached-body validations in StaticFiles. Requests still stat the target; its changed body may remain cached until the TTL expires. 0 validates each request. Applies only with cache=True, separately in each worker.

HTTP/2 internals

Variable Default Controls
BB_H2_INITIAL_WINDOW_SIZE 65535 Per-stream inbound flow-control window advertised in initial SETTINGS. Larger values allow more in-flight data per stream before WINDOW_UPDATE.
BB_H2_CONNECTION_WINDOW_SIZE 65535 Inbound connection-level flow-control window opened by initial WINDOW_UPDATE. Values below 65535 are ignored.
BB_H2_MAX_CONCURRENT_STREAMS 100 SETTINGS_MAX_CONCURRENT_STREAMS (RFC 9113 §6.5.2 id 0x3). Streams beyond the cap receive RST_STREAM REFUSED_STREAM and are not dispatched.
BB_WORKER_DRAIN_TIMEOUT 8.0 Seconds to let accepted connections finish after SIGTERM before cancelling remaining work, in single- and multi-worker serving. 0 cancels immediately. Keep this below the supervisor's stop budget. See Shutdown.
BB_H2_ACTIVE_STREAMS 20 Per-connection asyncio.Semaphore cap on stream handlers actually running concurrently, under multi-worker. Prevents one high-mux connection from saturating a single event loop. 0 disables (no cap beyond BB_H2_MAX_CONCURRENT_STREAMS).
BB_H2_ACTIVE_STREAMS_1W 20 Same as above, but used when BB_WORKERS=1.
BB_FRAME_YIELD_EVERY 8 Stream tasks spawned before the HTTP/2 frame loop yields cooperatively. 0 disables yielding.

WebSocket

Variable Default Controls
BB_WS_PERMESSAGE_DEFLATE 1 Negotiate permessage-deflate (RFC 7692) on the inbound handshake when the peer offers it.
BB_WS_MAX_FRAME_PAYLOAD 67108864 (64 MiB) Maximum declared payload length of a single inbound frame, checked against the header before any payload byte is read — RFC 6455 §5.2 permits a peer to advertise 263−1. Exceeding it closes with 1009 (Message Too Big).
BB_WS_MAX_MESSAGE_SIZE 16777216 (16 MiB) Inbound WebSocket message bytes after reassembly and decompression. Excess closes with 1009 and logs ws_max_message_size without materializing the oversized message. 0 disables. Lower this if the application does not need large messages; a frame cap alone cannot bound inflated or fragmented totals.
BB_WS_IDLE_TIMEOUT 300.0 Seconds of WebSocket silence before a server liveness PING. Any inbound frame answers; no answer within BB_WS_PONG_TIMEOUT closes with 1001. Server-side only; clients do not probe. 0 disables.
BB_WS_PONG_TIMEOUT 30.0 Seconds to wait for any inbound frame after a liveness PING, then close with 1001. Applies only with a non-zero BB_WS_IDLE_TIMEOUT.
BB_H2_ENABLE_WEBSOCKET 0 Advertise ENABLE_CONNECT_PROTOCOL=1 for RFC 8441 WebSocket. Review BB_MAX_CONNECTIONS and BB_H2_WS_MAX_STREAMS_PER_CONNECTION before exposing this path. A proxy forwarding HTTP/1.1 does not provide Extended CONNECT.
BB_FRAME_RATE_LIMIT 20 Control frames per type, per connection, per rolling window. Meters H2 RST_STREAM (inbound and server-emitted), PING, SETTINGS, empty CONTINUATION/DATA and WebSocket controls. Excess: H2 GOAWAY(ENHANCE_YOUR_CALM), WS close 1008, and frame_rate cap log. 0 disables.
BB_FRAME_RATE_WINDOW 1.0 Width in seconds of the rolling window BB_FRAME_RATE_LIMIT counts within.
BB_H2_IDLE_TIMEOUT 300.0 Seconds of HTTP/2 silence before a server liveness PING. Any inbound frame answers. Idle connections are probed, not closed immediately. 0 disables probing.
BB_H2_PING_TIMEOUT 30.0 Seconds to wait for any frame after a liveness PING before concluding the peer is gone and closing with GOAWAY(NO_ERROR). Only meaningful when BB_H2_IDLE_TIMEOUT is non-zero.
BB_H2_WS_MAX_STREAMS_PER_CONNECTION 5 Maximum concurrent WebSocket (RFC 8441 Extended CONNECT) streams per HTTP/2 connection. Caps the per-connection blast radius of WS-over-H2 stream-exhaustion attacks. Excess streams receive RST_STREAM REFUSED_STREAM. 0 disables the cap (no upper bound beyond BB_H2_MAX_CONCURRENT_STREAMS). Only meaningful when BB_H2_ENABLE_WEBSOCKET=1.

MQTT

MQTT advertises limits where CONNACK defines a property. The inbound Receive Maximum relies on peer compliance; it is not an enforced admission gate.

Variable Default Controls
BB_MQTT_MAX_PACKET_SIZE 1048576 (1 MiB) Maximum inbound packet size including its fixed header, advertised as Maximum Packet Size (§3.2.2.3.6) and checked before waiting for the body. Exceeding it closes silently before CONNECT admission, otherwise with DISCONNECT 0x95 (Packet Too Large). 0 disables.
BB_MQTT_BROKER_INBOX_MAXSIZE 1024 Positive bound on messages waiting in the worker's MQTT broker inbox. Readers await admission at capacity; the broker logs the cap hit. Independent of session QoS backlog. Invalid values, including zero, use the default.
BB_MQTT_BROKER_INBOX_MAX_BYTES 16777216 (16 MiB) Positive wire-size budget for broker inbox contents, alongside the count cap. Compact ACK/lifecycle envelopes charge one byte and one slot. A single packet exceeding the budget closes the connection: silently before CONNECT admission, otherwise with DISCONNECT 0x97. Not a heap budget; active processing and each reader's admission candidate are outside the queue. Invalid values use the default.
BB_MQTT_CONNECTION_INBOX_MAXSIZE 1024 Positive bound on all packets waiting for each MQTT writer, including QoS 0 and ACKs. The producer yields to the writer at capacity, then logs and ends only that connection if it cannot admit the packet; it never waits for socket progress inside the broker. Invalid values, including zero, use the default.
BB_MQTT_CONNECTION_INBOX_MAX_BYTES 16777216 (16 MiB) Positive encoded-byte budget for each MQTT writer inbox. The packet object is retained alongside encoded bytes. One active write is outside this queue budget and uses BB_WRITE_TIMEOUT. Tune with the accepted packet size; an individually larger packet cannot fit even in an empty queue. Like the count cap, a packet that cannot be admitted ends only that connection. Invalid values use the default.
BB_MQTT_RECEIVE_MAXIMUM 64 Advertised inbound QoS>0 in-flight maximum. This relies on client compliance and is not an enforced admission gate. Outbound delivery enforces the client's Receive Maximum and uses BB_MQTT_MAX_QUEUED_MESSAGES for backlog.
BB_MQTT_MAX_QUEUED_MESSAGES 1000 QoS>0 backlog per session while the client's Receive Maximum window is full. At the cap, refuse newest and log; retain older promised messages. 0 disables.
BB_MQTT_MAX_RETAINED 10000 Retained topics. At capacity refuse new stored topics; updates, deletion and live delivery still work. QoS 1/2 report 0x97 in PUBACK/PUBREC; QoS 0 has no acknowledgement. Use QoS ≥ 1 to learn whether storage succeeded. Every refusal logs. 0 disables.
BB_MQTT_MAX_SUBSCRIPTIONS 1000 Topic Filters per session. New filters at capacity receive SUBACK 0x97 and a cap log; replacing an existing filter remains allowed. 0 disables.
BB_MQTT_MAX_SESSIONS 10000 Retained sessions after expired entries are swept. At capacity unknown Client Identifiers receive CONNACK 0x97 and close; resuming an existing session remains allowed. Never-expiring sessions consume this total without a clock bound. 0 disables.

gRPC

Read once at import, so a change needs a restart. Tests monkeypatch the module attribute rather than the variable.

Variable Default Controls
BB_GRPC_MAX_MESSAGE_SIZE 4194304 (4 MiB) Largest gRPC message accepted on a call. Matches grpcio's own default receive limit, so a client tuned against grpcio meets the same ceiling here. A value that does not parse falls back to the default rather than failing the import.
BB_GRPC_STREAM_BATCH_BYTES 16384 Response-message bytes gathered before a streaming write. Flush partial batches when the producer suspends, at call end and before trailing status; DATA boundaries do not delimit gRPC messages.
BB_GRPC_COMPRESS_MIN_BYTES 1024 Responses below this size are sent uncompressed. gzip's header and trailer can make a small message larger, so the threshold avoids spending CPU for no bandwidth. Set it very high to disable response compression outright.

Compression

Variable Default Controls
BB_COMPRESSION_MIN_SIZE 100 Minimum body size in bytes below which the Compression middleware skips compression entirely.
BB_COMPRESSION_EXECUTOR_THRESHOLD 65536 Body size above which compression is offloaded to a thread-pool executor so the event loop stays responsive during the (CPU-bound) compress call. 0 always compresses on the event loop.
BB_COMPRESSION_MAX_INFLIGHT max(cpu_count() * 2, 4) Maximum concurrent compression offloads. At the cap, serve eligible responses uncompressed rather than queue them. 0 disables admission limiting.
BB_BROTLI_QUALITY 4 Dynamic-response Brotli quality (0–11). Reserve the highest levels for build-time precompression, not request handling.

Diagnostic timing

Variable Default Controls
BB_PHASE_TRACE 0 Record per-request wall-clock and CPU checkpoints in access-log phases. Off by default; enable for diagnostics.
BB_DEADLINE_TICK_MS 300.0 Milliseconds between shared deadline-scanner ticks. Smaller values tighten enforcement granularity at a CPU cost; larger values allow more deadline slack.

Tuning a deployment

Tune backlog, connection counts, socket buffers and HTTP/2 windows together against the workload's memory budget. Their scope depends on the bind path; see Workers and the startup window.

See also

  • Configuration — how environment variables compose with TOML config files and CLI flags.
  • Logging — BB_ACCESS_LOG and BB_ASYNC_LOGGING semantics.
  • HTTP/2 — what the BB_H2_* knobs control end-to-end.