Skip to main content

pygrpc-native

A gRPC server for Python whose HTTP/2 and gRPC work runs in Rust, outside the GIL. Your handlers stay in Python.

When a Python gRPC server runs out of CPU, the usual fixes are running more server processes or rewriting the servicers in another language. pygrpc-native instead moves the gRPC work itself (framing, flow control, deadlines and cancellation) onto a tokio runtime outside the GIL, and leaves your servicers, interceptors and generated code alone, so Python spends its time on your code. pygrpc_native.server() and pygrpc_native.aio.server() take the same arguments as grpcio's servers, so switching is usually a one-line change, and nothing changes for clients.

Underneath, each call reaches Python as an event: an id, the method, the request bytes and who sent it.

grpc client ──HTTP/2──▶ tokio threads (no GIL)
                          │ path → method id
                          ▼
                    event queue ──▶ recv_batch() in Python
                          ◀── respond(call_id, bytes) from any thread

Calls reach Python in batches, so a burst takes one trip across the GIL rather than one per call.

Install

pip install pygrpc-native

Wheels are published for Linux (x86_64, aarch64) and macOS (arm64, x86_64) and work on CPython 3.10 and later. To build from a checkout:

pip install maturin
maturin develop --release

With grpcio servicers

pygrpc_native.server() takes the same arguments as grpc.server() and serves servicers from grpcio-tools generated code (1.64 or later) unchanged:

from concurrent import futures
import pygrpc_native

server = pygrpc_native.server(futures.ThreadPoolExecutor(16))
greeter_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port("[::]:50051")
server.start()
server.wait_for_termination()

Status codes, error messages, metadata, deadlines, cancellation and ServicerContext behave as they do in grpcio.

Unary and server-streaming methods are served natively on one insecure port. The rest, such as client-streaming and bidirectional methods, server reflection, or handlers added only with add_generic_rpc_handlers, as code generated by grpcio-tools before 1.64 does, go to a grpcio server on a Unix socket behind it. They work, but they aren't any faster, and peer() in them is the socket.

Interceptors run as in grpcio, on the methods served here and on the fallback server. Of the server options, the message size limits, the keepalive settings (grpc.keepalive_time_ms, grpc.keepalive_timeout_ms and grpc.keepalive_permit_without_calls), grpc.max_concurrent_streams and the metadata size limits (grpc.max_metadata_size and grpc.absolute_max_metadata_size) work as in grpcio. Options that ask for something this server can't do raise an error: closing connections by age or idleness (grpc.max_connection_age_ms, grpc.max_connection_age_grace_ms, grpc.max_connection_idle_ms), grpc.max_allowed_incoming_connections and response compression, as do maximum_concurrent_rpcs and TLS. Any other option is ignored, as grpcio ignores the many that only clients read. That covers the limits on client pings, which are accepted but not enforced, and grpc.http2.max_frame_size, which grpc-core's flow control overrides anyway. Values that aren't integers are ignored too, as in grpcio.

There are two known differences. If a unary handler calls send_initial_metadata() and then fails, the metadata goes out with the status, so the client sees it as trailing metadata. And a connection whose client doesn't answer a keepalive ping is closed after grpc.keepalive_timeout_ms, as gRPC's keepalive documentation describes, while grpcio waits for grpc.http2.ping_timeout_ms, a minute by default.

pygrpc_native.aio.server() does the same for grpc.aio.server():

import pygrpc_native.aio

server = pygrpc_native.aio.server()
greeter_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port("[::]:50051")
await server.start()
await server.wait_for_termination()

Handlers run on the event loop that called start(), uvloop included. abort() raises grpc.aio.AbortError, and a handler whose client cancels or whose deadline passes gets asyncio.CancelledError, as in grpc.aio. Streams can yield from an async generator or call context.write(), and handlers that aren't coroutines run in migration_thread_pool with grpcio's sync context, where abort() returns instead of raising. The fallback, the unsupported options and the known differences are the same as for the sync server.

Low-level API

NativeGrpcFront is the layer under server(). Each call reaches Python as an event that you answer by id:

import threading
from pygrpc_native import EVENT_CALL, NativeGrpcFront

front = NativeGrpcFront("0.0.0.0:50051", [("/echo.Echo/Say", False)])
front.start()

def serve():
    while (events := front.recv_batch(64)) is not None:
        for kind, call_id, method_id, payload, client_key in events:
            if kind == EVENT_CALL:
                front.respond(call_id, payload)

threading.Thread(target=serve).start()

Streaming, call details, response metadata, bearer tokens and metrics are covered in docs/low-level-api.md.

Compatibility

pygrpc-native follows semantic versioning, and the low-level API stays compatible within 0.x as well. tests/test_api.py pins the 0.1 names, signatures and event tuples of NativeGrpcFront: they won't change or go away, and new parameters only come after the existing ones, with a default. The keys metrics() returns won't be renamed or removed within 0.x either, though new ones may be added. server() and aio.server() follow grpcio's API, and any difference from grpcio's behavior is a bug unless it is listed in this README. Changes are listed in CHANGELOG.md.

Limitations

  • NativeGrpcFront serves unary and server-streaming methods only; other kinds can go through the fallback server. server() and aio.server() send them there on their own.
  • No TLS yet. NativeGrpcFront checks bearer tokens itself; server() and aio.server() run grpcio interceptors instead.
  • Like grpc-core, binding a Unix socket path replaces any socket file already there.
  • The server sets SO_REUSEPORT only when grpc.so_reuseport is 1. grpcio sets it by default, so binding a port another server already uses succeeds with grpcio but fails here.
  • Per connection: at most 1024 concurrent streams unless grpc.max_concurrent_streams says otherwise. A connection that hasn't finished the HTTP/2 preface after 120 s is dropped.
  • A call with more request metadata than the limit (16 KiB unless set) is refused. grpcio also refuses some calls at random between grpc.max_metadata_size and that limit; this server doesn't.

Benchmarks

With an empty handler on an Apple M4 Pro, pygrpc_native.server() answers about 1.5x the calls per second of grpc.server() from one client thread and about 5x from 32. On a 40-vCPU Linux container the low-level API answered about 12x at 32 threads. See benchmarks for the numbers and how they were measured.

Contributing

See CONTRIBUTING.md. Every commit needs a DCO sign-off (git commit -s).

License

Apache-2.0

Metadata

Release files for pygrpc-native 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pygrpc-native 0.5.0
File Size Uploaded Provenance Actions
pygrpc_native-0.5.0.tar.gz 199.4 kB With provenance Details for pygrpc_native-0.5.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for pygrpc-native 0.5.0
File Actions
pygrpc_native-0.5.0-cp310-abi3-manylinux_2_28_x86_64.whl CPython 3.10 abi3 Linux glibc 2.28+ x86-64 Details for pygrpc_native-0.5.0-cp310-abi3-manylinux_2_28_x86_64.whl
pygrpc_native-0.5.0-cp310-abi3-manylinux_2_28_aarch64.whl CPython 3.10 abi3 Linux glibc 2.28+ ARM64 Details for pygrpc_native-0.5.0-cp310-abi3-manylinux_2_28_aarch64.whl
pygrpc_native-0.5.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details for pygrpc_native-0.5.0-cp310-abi3-macosx_11_0_arm64.whl
pygrpc_native-0.5.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details for pygrpc_native-0.5.0-cp310-abi3-macosx_10_12_x86_64.whl

Total release size: 4.6 MB

Release files / pygrpc_native-0.5.0.tar.gz

Download URL pygrpc_native-0.5.0.tar.gz
Size 199.4 kB
Tags Source
SHA-256 checksum
How to use checksums
9fa2de6543291c5a2beeabac0a03fd88b6e27ac09e236e1858281c656271843a
BLAKE2b-256 checksum
How to use checksums
463a79145df001b6c4009afee2b45ca517f394c987259e13ae9159aa7aa15084
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Release files / pygrpc_native-0.5.0-cp310-abi3-manylinux_2_28_x86_64.whl

Download URL pygrpc_native-0.5.0-cp310-abi3-manylinux_2_28_x86_64.whl
Size 1.1 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
97058d5a31fbede1237bf9697153d26ec05e38c81ad60099679c907cf7d2821b
BLAKE2b-256 checksum
How to use checksums
98c84ecd9a33b7668540cd8bbb046d139a2b363708fe9eff51104cf562bc4af0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Release files / pygrpc_native-0.5.0-cp310-abi3-manylinux_2_28_aarch64.whl

Download URL pygrpc_native-0.5.0-cp310-abi3-manylinux_2_28_aarch64.whl
Size 1.1 MB
Tags CPython 3.10 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
a3ea289a6ea7d8801a404c7cea2debb0662497ec9a9b7cb5a6feee04f5bf2595
BLAKE2b-256 checksum
How to use checksums
60d926a0aa22607c8b808ca578bf3262e68b7e02b035c4accd74e045c2966386
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Release files / pygrpc_native-0.5.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL pygrpc_native-0.5.0-cp310-abi3-macosx_11_0_arm64.whl
Size 1.0 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
86d3fa8771b2a6d6acc9a656a8a12e031e84e61890fb00ac69042af8b9d5ab8c
BLAKE2b-256 checksum
How to use checksums
86556303fc6f12eb8e505b04479fc3b2981479b835a766c59d7749e0028cbad4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Release files / pygrpc_native-0.5.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL pygrpc_native-0.5.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 1.1 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
ecdc8d03d58fb6984a22b892b96344a7f9f7de17a6cc171e7e354fd37c2bb5d7
BLAKE2b-256 checksum
How to use checksums
28edcb52838b10c683c8fde8ed52817fdab0c210778b7621035babbc0935447f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Security for pygrpc-native 0.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 5 files in this release have been uploaded with provenance metadata.

Select from 5 files

Attestation for pygrpc_native-0.5.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page