Skip to main content

pygrpc-native

pygrpc-native

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

PyPI Python versions CI License

With grpc.server(), C-core does HTTP/2 and Python handles each call's events one at a time under the GIL. With pygrpc_native.server(), Rust threads do HTTP/2 and the per-call work outside the GIL and hand calls to Python in batches.

When a Python gRPC server runs short of CPU, the usual answers are more server processes or a rewrite in another language. pygrpc-native moves the gRPC work itself (HTTP/2, flow control, deadlines, cancellation) into Rust, outside the GIL, and leaves your servicers, interceptors and generated code as they are.

  • Switching is one line. pygrpc_native.server() and pygrpc_native.aio.server() take the same arguments as grpcio's servers. Clients don't change.
  • It behaves like grpcio. Status codes, metadata, deadlines, cancellation, interceptors and ServicerContext work the same way. The few differences are listed below, and anything else is a bug.
  • Nothing stops working. Methods it can't serve itself, such as bidirectional streaming or server reflection, are passed to a grpcio server running behind it.
  • It's faster under load. With an empty handler it answers about 1.5x as many calls per second as grpcio from one client thread, and about 5x from 32. See Benchmarks.

Quick start

pip install pygrpc-native

Wheels are available for Linux (x86_64, aarch64) and macOS (arm64, x86_64), for CPython 3.10 and later.

Change the line that creates the server:

 from concurrent import futures
-import grpc
+import pygrpc_native

-server = grpc.server(futures.ThreadPoolExecutor(16))
+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()

For grpc.aio:

+import pygrpc_native.aio
+
-server = grpc.aio.server()
+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()

To build from source:

pip install maturin
maturin develop --release

How it works

Every 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

Python picks up calls in batches, so a burst costs one trip across the GIL instead of one per call. server() and aio.server() are built on top of this and run your handlers the way grpcio does.

What runs natively

Native grpcio fallback
Unary and server-streaming methods ✓
Client-streaming and bidirectional methods ✓
Code generated by grpcio-tools 1.64 or later ✓
Code generated by older grpcio-tools, or anything else added only with add_generic_rpc_handlers ✓
Server reflection ✓
Interceptors ✓ ✓

The fallback is a grpcio server listening on a Unix socket behind this one. Calls that go there work but aren't any faster, and peer() in them returns the socket. The native server listens on a single insecure port.

Server options
Options
Same as grpcio grpc.max_receive_message_length, grpc.max_send_message_length, grpc.keepalive_time_ms, grpc.keepalive_timeout_ms, grpc.keepalive_permit_without_calls, grpc.max_concurrent_streams, grpc.max_metadata_size, grpc.absolute_max_metadata_size, grpc.so_reuseport
Raise an error grpc.max_connection_age_ms, grpc.max_connection_age_grace_ms, grpc.max_connection_idle_ms, grpc.max_allowed_incoming_connections, response compression, maximum_concurrent_rpcs, TLS
Ignored Everything else. grpcio also ignores the many options that only clients read. This includes 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.

As in grpcio, a value that isn't an integer is ignored.

Known differences from grpcio
  • If a unary handler calls send_initial_metadata() and then fails, the metadata is sent along with the status, so the client sees it as trailing metadata.
  • If a client doesn't answer a keepalive ping, the connection is closed after grpc.keepalive_timeout_ms, as gRPC's keepalive docs describe. grpcio waits for grpc.http2.ping_timeout_ms instead, which is a minute by default.
Notes on aio.server()
  • Handlers run on the event loop that called start(), including uvloop.
  • abort() raises grpc.aio.AbortError. If the client cancels or the deadline passes, the handler gets asyncio.CancelledError, as in grpc.aio.
  • Streaming handlers can yield from an async generator or call context.write().
  • Handlers that aren't coroutines run in migration_thread_pool with grpcio's sync context, where abort() returns instead of raising.
  • The fallback, the options and the differences above are the same as for the sync server.

Low-level API

NativeGrpcFront is the layer under server(). You receive each call as an event and answer it 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.

Benchmarks

benchmarks/echo.py against grpc.server(), then against pygrpc_native.server()

An empty unary handler on an Apple M4 Pro, called by grpcio clients on the same machine. Calls per second, median of three runs:

Server 1 client thread 32 client threads (8 processes x 4)
grpc.server() 7,739 10,955
grpc.aio.server() 4,804 10,322
pygrpc_native.server() 11,428 57,419
pygrpc_native.aio.server() 9,444 58,073
Low-level API 12,835 63,413

On a 40-vCPU Linux container, the low-level API answered about 12x as many calls as grpcio at 32 threads. The benchmark README has all the numbers and explains how they were measured.

Limitations

  • NativeGrpcFront only serves unary and server-streaming methods. Other kinds can go through the fallback server, and server() and aio.server() send them there for you.
  • There's no TLS yet. NativeGrpcFront checks bearer tokens itself, while server() and aio.server() run grpcio interceptors.
  • As with grpc-core, binding a Unix socket path replaces any socket file already there.
  • SO_REUSEPORT is set only when grpc.so_reuseport is 1. grpcio sets it by default, so binding a port that another server already uses works with grpcio but fails here.
  • Each connection allows up to 1024 concurrent streams unless grpc.max_concurrent_streams says otherwise. A connection that hasn't finished the HTTP/2 preface within 120 s is dropped.
  • A call whose request metadata is over the limit (16 KiB unless set) is refused. Between grpc.max_metadata_size and that limit, grpcio also refuses some calls at random. This server doesn't.

Compatibility

pygrpc-native follows semantic versioning, and the low-level API also stays compatible within 0.x:

  • The 0.1 names, signatures and event tuples of NativeGrpcFront won't change or go away. tests/test_api.py pins them. New parameters are only added after the existing ones, with a default.
  • The keys that metrics() returns won't be renamed or removed within 0.x, though new ones may be added.
  • server() and aio.server() follow grpcio's API. Any difference from grpcio's behavior is a bug unless this README lists it.

Changes are listed in CHANGELOG.md.

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.2

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.2
File Size Uploaded Provenance Actions
pygrpc_native-0.5.2.tar.gz 201.8 kB With provenance Details for pygrpc_native-0.5.2.tar.gz

Built distributions (wheels)

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

Total release size: 4.6 MB

Release files / pygrpc_native-0.5.2.tar.gz

Download URL pygrpc_native-0.5.2.tar.gz
Size 201.8 kB
Tags Source
SHA-256 checksum
How to use checksums
9696293b950e5825b1ac5a0b158a0b584c8b11a6cb996e411a745ba4cba2d66b
BLAKE2b-256 checksum
How to use checksums
55a6340163f841df80c27c4502a26338ab176cd38c8b086ef7fe8a8e44ea3067
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 28, 2026.

Transparency log

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

Download URL pygrpc_native-0.5.2-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
b903a1ee8b6f8b89297b994da9870603c907865ea4ab7e31507f5ee1524513e8
BLAKE2b-256 checksum
How to use checksums
10bfee51f9d1fa8c96a6f012d418f8e1296c5447a4295b097ad48b8dda629b72
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 28, 2026.

Transparency log

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

Download URL pygrpc_native-0.5.2-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
8a0079517abd3adc2b9db961dac146c222c6a7b2f9585e87e68d2f88f17faf47
BLAKE2b-256 checksum
How to use checksums
7d76b5a5ce16f441c9cd9a71c9f3447a58a3b64f48cc2fd3730495f8ff4acf44
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 28, 2026.

Transparency log

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

Download URL pygrpc_native-0.5.2-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
05fe5c83f483a6d8efb8048b2b6d9b6ec321574173e20d5b7936088289712dca
BLAKE2b-256 checksum
How to use checksums
b61071499274da0339f893ab7746ce78d488d33e72434722efe572b77c3c5399
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 28, 2026.

Transparency log

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

Download URL pygrpc_native-0.5.2-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
5708cacc74f7f26ed023574979aaa237c7f86441e2ef16968dd1977367f1891a
BLAKE2b-256 checksum
How to use checksums
15eab24e47fd174c7600ceb4e8440162a8964e8d93e5ddefb87ff620661ad173
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 28, 2026.

Transparency log

Security for pygrpc-native 0.5.2

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.2.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 28, 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