¶
fastpg is a fast async PostgreSQL client for Python, written in Rust. It turns rows straight into msgspec Structs, so you get typed objects back with no extra code.
import asyncio
import msgspec
import fastpg
class Person(msgspec.Struct):
name: str
age: int
async def main() -> None:
dsn = "postgresql://fastpg:fastpg@127.0.0.1:55432/fastpg"
async with await fastpg.create_pool(dsn) as pool:
query = "SELECT name, age FROM people WHERE id = $1"
person = await pool.select_one(query, 42, into=Person)
print(person) # Person(name='person-42', age=60)
asyncio.run(main())
New here? Start with Getting started.
What you get¶
- Typed rows.
into=Persongives you Structs. See Structs. - A pool you query directly. No
acquire()for a single query. See Connection pool. - Safe parameters.
$1,:nameor t-strings. See Queries. - Arrays and grouping.
list[X]fields, lists as parameters, andselect_and_groupfor one-to-many rows. See Arrays and grouping. - Fast bulk writes.
copy_in,insert_many,execute_many. See Bulk writes. - Transactions, TLS and clear errors. See Transactions, TLS and Errors.
- pydantic too. If your app uses pydantic, see pydantic models.
Speed¶
| workload | fastpg | fastest other driver | speed-up |
|---|---|---|---|
| Primary-key lookup into a Struct, 16 tasks | 39,774/s | 17,144/s (asyncpg) | 2.32x |
| Page of 20 rows into Structs, 16 tasks | 19,002/s | 9,094/s (asyncpg) | 2.09x |
| 1,000 rows into Structs, 4 tasks | 1.03M rows/s | 476k rows/s (asyncpg) | 2.15x |
| Single-row INSERT, 16 tasks | 35,860/s | 16,087/s (asyncpg) | 2.23x |
| Binary COPY, 5,000 rows | 1.16M rows/s | 823k rows/s (psycopg) | 1.41x |
All workloads and how they're measured: Benchmarks.
fastpg is alpha software. See what it can't do yet in Limitations.