Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

pyro-postgres is a high-performance PostgreSQL driver for Python, backed by Rust. It provides both synchronous and asynchronous APIs with a focus on speed and ergonomics.

pip install pyro-postgres

Quick Start

from pyro_postgres.sync import Conn

conn = Conn("pg://user:password@localhost/mydb")

# Simple query
rows = conn.query("SELECT id, name FROM users")

# Parameterized query
user = conn.exec_first("SELECT * FROM users WHERE id = $1", (42,))

# Transaction
with conn.tx():
    conn.exec_drop("INSERT INTO users (name) VALUES ($1)", ("Alice",))
    conn.exec_drop("INSERT INTO users (name) VALUES ($1)", ("Bob",))

Features

  • High Performance: Minimal allocations and copies
  • Sync and Async: The library provides both sync and async APIs
  • Pipelining: Batch multiple queries in a single round trip
  • Streaming: Process large result sets without loading everything into memory

Comparisons

pyro-postgres is built on zero-postgres, providing significant performance benefits over pure Python implementations.

Querypyro-postgrespsycopgSpeedup
SELECT 1 row39 us104 us2.7x faster
SELECT 10 rows46 us113 us2.4x faster
SELECT 100 rows112 us178 us1.6x faster
SELECT 1000 rows570 us810 us1.4x faster
INSERT6 us20 us3.0x faster

Limitations

  • Python 3.10+: Requires Python 3.10 or later
  • PostgreSQL 18: Supports PostgresSQL 18 or later
  • Limited Type Coverage: Not all PostgreSQL types are supported yet
  • Limited Performance Gain in Async API: Due to the overhead of Python 3.14 Free-threading, the async module pays a significant cost switching between Python thread and Rust thread. Upon receiving the network packet, the Rust thread needs to attach to GIL to construct objects like PyList/PyInt/PyString and detach soon after. It was observed in one of the benchmarks that more than 30% time is spent on the destruction of GILState c struct. To avoid this, we accumulate the received row data in the Rust buffer and convert to Python at once. The async performance has a potential to be much faster than now with the advance of single-threaded overhead of Python Free-threading.