Python SDK

Production

Run Python Serve as a hardened standalone process, with per-process budgets wherever it is served.

A ProductionProfile sets process budgets: admission, request deadlines and result sizes. start_server runs an API created with one as a hardened standalone process:

from hypequery.serve import HttpSecurity, ProductionProfile, create_api, start_server

api = create_api(
    auth=authenticate,
    client=client,
    datasets={"orders": orders},
    security=HttpSecurity(
        allowed_hosts=("analytics.example.com",),
        trusted_proxies=("127.0.0.1",),
    ),
    production=ProductionProfile(
        max_concurrency=32,
        timeout_seconds=30,
        max_result_rows=10_001,
        max_result_bytes=8 << 20,
    ),
)

if __name__ == "__main__":
    start_server(api)

start_server needs the server extra (pip install "hypequery[server]==0.1.0b2"). run_production is the same function. To close an executor at shutdown, pass the ASGI app with a lifespan: start_server(to_asgi_app(api, lifespan=...)).

Process

  • Binds to 127.0.0.1:8000 by default (ProductionProfile(host=..., port=...)). Binding outside loopback, for example inside a container, requires allow_external_bind=True.
  • Runs one uvicorn worker per process with reload, access logging, server headers, and WebSockets disabled. Use a process manager to run several instances; limits apply per instance.
  • Terminate TLS at a reverse proxy and list its addresses in HttpSecurity.trusted_proxies. Production rejects all-address networks, and uvicorn's own forwarded-header handling is turned off so proxy trust is decided once.
  • create_api refuses a production profile without an HttpSecurity, with development docs, or with from_context(..., same_origin=False). A header credential (bearer, API key, JWT) is never read from a cookie; your app's session is read only by a from_context strategy, with its same-origin check. hypequery dev refuses to run a production API.

Limits

SettingDefaultEffect
max_concurrency32Excess in-flight requests get 503 SERVICE_UNAVAILABLE without queuing
timeout_seconds30Covers auth, body, query, and response; expiry cancels the query and returns 504
max_result_rows10,001Includes the one-row pagination probe, so at most 10,000 rows are returned
max_result_bytes8 MiBApplies to ClickHouse results and the serialized response; oversized bodies get 413
max_threads4ClickHouse thread ceiling per query

Time, row, byte, and thread ceilings are passed into the compiled query and intersected with stricter client settings. Responses are buffered under the byte ceiling, so this profile does not provide streaming exports.

A request that times out keeps its admission slot until the work it started has stopped, so timed-out requests can't pile up. Work still waiting for a worker thread is cancelled before your code starts. Synchronous executors must honor the cancellation signal: the ClickHouse executor does, through its control connection, but Python cannot stop arbitrary code already running in a thread.

Mounted in another app

The profile's budgets apply wherever the API is served, including when it is mounted in another application or served through the Django and Flask adapters. The host application owns its own process settings and safeguards for everything else it serves.

On this page

Get early access to hypequery cloud.

Cloud hosts the same model you run in your backend, with a managed API and MCP server, versions, and rollback. We're letting teams in a few at a time. Join the waitlist and we'll reach out when your project can go live.

How do you want to build your analytics layer? (Optional)
What features do you most need? (Optional)

Pick as many as you like.

Only your email is required. All other questions are optional.